10 Commits

Author SHA1 Message Date
f802e28d26 doc: add kiosk mode
All checks were successful
arcad/arcast/pipeline/pr-develop This commit looks good
2024-05-02 11:50:33 +02:00
16f5e1873d doc: text correction
All checks were successful
arcad/arcast/pipeline/pr-develop This commit looks good
2024-04-30 16:28:45 +02:00
a4784e9226 doc: add img for exemple 2024-04-30 16:27:42 +02:00
5039a9d5c2 doc: add link for the two new document 2024-04-30 15:40:04 +02:00
83fd962ac8 doc: add some detail for the extra configuration 2024-04-30 15:39:35 +02:00
653f4cc91b doc: create doc usage for user 2024-04-30 15:38:54 +02:00
0a15c96339 doc: create doc installation 2024-04-30 15:38:19 +02:00
b8ddd0018c feat: add screen for doc 2024-04-30 15:37:50 +02:00
384b351fbc fix(android): versionName/versionCode injection
All checks were successful
arcad/arcast/pipeline/head This commit looks good
2024-04-29 19:11:50 +02:00
7c75b478a3 feat(android): use native webview instead of gioui framework
All checks were successful
arcad/arcast/pipeline/head This commit looks good
2024-04-29 11:51:45 +02:00
25 changed files with 653 additions and 352 deletions

View File

@ -1,5 +1,4 @@
{
"java.project.sourcePaths": [
"apps/main/src"
]
}
"java.project.sourcePaths": ["apps/main/src"],
"java.configuration.updateBuildConfiguration": "automatic"
}

View File

@ -1,3 +1,5 @@
export PATH := $(PATH):$(PWD)/tools/gomobile/bin:$(PWD)/tools/gobind/bin
LINT_ARGS ?= --timeout 5m
GORELEASER_VERSION ?= v1.25.1
GORELEASER_ARGS ?= release --snapshot --clean
@ -50,9 +52,13 @@ build-client: deps ## Build executable
-o ./bin/client \
./cmd/client
build-android: .mktools tools/gogio/bin/gogio deps ## Build executable
.PHONY: android/app/libs/arcast.aar
android/app/libs/arcast.aar: tools/gomobile/bin/gomobile tools/gobind/bin/gobind
mkdir -p android/app/libs
gomobile bind -v -javapkg com.cadoles.arcast -target android -o android/app/libs/arcast.aar ./pkg/android
build-android: .mktools android/app/libs/arcast.aar deps ## Build executable
mkdir -p dist
CGO_ENABLED=1 GOOS=android CGO_CFLAGS="-I${JDK_PATH}/include -I${JDK_PATH}/include/linux -w" tools/gogio/bin/gogio -target android -buildmode archive -o android/app/libs/mobile.aar -x ./cmd/mobile
( cd android && VERSION_CODE=$(VERSION_CODE) VERSION_NAME=$(MKT_PROJECT_VERSION)-debug ./gradlew assembleDebug )
$(ANDROID_KEYSTORE_FILE):
@ -64,9 +70,8 @@ $(ANDROID_KEYSTORE_FILE):
-validity $(ANDROID_KEYSTORE_KEY_VALIDITY) \
-storepass "$(ANDROID_KEYSTORE_PASS)"
release-android: $(ANDROID_KEYSTORE_FILE) tools/gogio/bin/gogio deps ## Build executable
release-android: deps .mktools android/app/libs/arcast.aar $(ANDROID_KEYSTORE_FILE) ## Build executable
mkdir -p dist
CGO_ENABLED=1 GOOS=android CGO_CFLAGS="-I${JDK_PATH}/include -I${JDK_PATH}/include/linux -w" tools/gogio/bin/gogio -target android -buildmode archive -o android/app/libs/mobile.aar -x ./cmd/mobile
( cd android && VERSION_CODE=$(VERSION_CODE) VERSION_NAME=$(MKT_PROJECT_VERSION) ./gradlew assemble )
rm -f android/app/build/outputs/apk/release/app-release-unsigned-aligned.apk
"$(ANDROID_HOME)/build-tools/$(ANDROID_BUILD_TOOLS_VERSION)/zipalign" -p 4 android/app/build/outputs/apk/release/app-release-unsigned.apk android/app/build/outputs/apk/release/app-release-unsigned-aligned.apk
@ -103,10 +108,6 @@ tools/modd/bin/modd:
mkdir -p tools/modd/bin
GOBIN=$(PWD)/tools/modd/bin go install github.com/cortesi/modd/cmd/modd@latest
tools/gogio/bin/gogio:
mkdir -p tools/gogio/bin
GOBIN=$(PWD)/tools/gogio/bin go install gioui.org/cmd/gogio@latest
release: gitea-release
gitea-release: .mktools build-apps goreleaser release-android
@ -134,6 +135,14 @@ gitea-release: .mktools build-apps goreleaser release-android
goreleaser: .env .mktools
( set -o allexport && source .env && set +o allexport && curl -sfL https://goreleaser.com/static/run | VERSION=$(GORELEASER_VERSION) GORELEASER_CURRENT_TAG="$(MKT_PROJECT_VERSION)" GOPATH=$(shell go env GOPATH) bash /dev/stdin $(GORELEASER_ARGS) )
tools/gomobile/bin/gomobile:
mkdir -p tools/gomobile/bin
GOBIN=$(PWD)/tools/gomobile/bin go install golang.org/x/mobile/cmd/gomobile@latest
tools/gobind/bin/gobind:
mkdir -p tools/gobind/bin
GOBIN=$(PWD)/tools/gobind/bin go install golang.org/x/mobile/cmd/gobind@latest
.PHONY: mktools
mktools:
rm -rf .mktools

View File

@ -3,13 +3,8 @@ plugins {
id 'org.jetbrains.kotlin.android'
}
def versionCode() {
return System.env.VERSION_CODE ? System.env.VERSION_CODE.toInteger() : 0
}
def versionName() {
return System.env.VERSION_NAME ? System.env.VERSION_NAME : "0.0.0"
}
def appVersionCode = Integer.valueOf(System.env.VERSION_CODE ?: 1)
def appVersionName = System.env.VERSION_NAME ?: "0.0.0"
android {
namespace 'com.cadoles.arcast_player'
@ -19,8 +14,8 @@ android {
applicationId "com.cadoles.arcast_player"
minSdk 24
targetSdk 34
versionCode versionCode()
versionName versionName()
versionCode appVersionCode
versionName appVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
@ -63,7 +58,7 @@ dependencies {
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3'
implementation files('libs/sys_android.jar')
implementation("androidx.webkit:webkit:1.10.0")
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

View File

@ -1 +1,2 @@
/mobile.aar
/mobile.aar
/arcast*

Binary file not shown.

View File

@ -8,8 +8,6 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
@ -35,12 +33,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="org.gioui.GioActivity"
android:theme="@style/Theme.GioApp"
android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="adjustResize"
android:keepScreenOn="true">
</activity>
</application>
</manifest>

View File

@ -0,0 +1,31 @@
package com.example.arcast_player
import android.webkit.WebView
import com.cadoles.arcast.android.Bridge
class ArcastBridge(private val webview: WebView) : Bridge {
private var title: String = ""
private var url: String = ""
override fun getTitle(): String {
return title
}
override fun getURL(): String {
return url
}
override fun loadURL(url: String) {
webview.post(Runnable {
webview.loadUrl(url)
})
}
fun setURL(url: String) {
this.url = url
}
fun setTitle(title: String) {
this.title = title
}
}

View File

@ -0,0 +1,18 @@
package com.example.arcast_player
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
class ArcastWebviewClient(private var bridge: ArcastBridge): WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
return false
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
bridge.title = view?.title.toString()
bridge.url = url.toString()
}
}

View File

@ -12,29 +12,26 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.cadoles.arcast_player.ui.theme.ArcastplayerTheme
import org.gioui.GioActivity
import android.view.WindowManager
import android.webkit.WebView
import com.cadoles.arcast.android.Android as Arcast
import com.example.arcast_player.ArcastBridge
import com.example.arcast_player.ArcastWebviewClient
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startActivity(Intent(this, GioActivity::class.java))
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
val wv = WebView(applicationContext)
val bridge: ArcastBridge = ArcastBridge(wv)
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
wv.webViewClient = ArcastWebviewClient(bridge)
Arcast.setBridge(bridge)
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
ArcastplayerTheme {
Greeting("Android")
val port = Arcast.startServer(filesDir.absolutePath)
wv.settings.javaScriptEnabled = true
wv.loadUrl("http://127.0.0.1:${port}")
setContentView(wv)
}
}

View File

@ -1,21 +1,22 @@
.root {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
}
.video {
object-fit: cover;
width: 100%;
height: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
height: auto;
left: 0;
object-fit: contain;
/* position: absolute; */
right: 0;
top: 0;
width: 100%;
flex-grow: 1;
width: 100%;
}

View File

@ -1,120 +0,0 @@
package main
import (
"context"
"crypto/tls"
"os"
"path/filepath"
"forge.cadoles.com/arcad/arcast"
"forge.cadoles.com/arcad/arcast/pkg/browser/gioui"
"forge.cadoles.com/arcad/arcast/pkg/config"
"forge.cadoles.com/arcad/arcast/pkg/server"
"gioui.org/app"
"gioui.org/io/system"
"gioui.org/layout"
"gioui.org/op"
"github.com/gioui-plugins/gio-plugins/plugin"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
const packageName = "com.cadoles.arcast_player"
func main() {
ctx := context.Background()
window := app.NewWindow(
app.Fullscreen.Option(),
app.AnyOrientation.Option(),
)
browser := gioui.NewBrowser(window)
go func() {
ops := new(op.Ops)
for {
evt := window.NextEvent()
plugin.Install(window, evt)
switch evt := evt.(type) {
case system.DestroyEvent:
os.Exit(0)
return
case system.FrameEvent:
gtx := layout.NewContext(ops, evt)
browser.Layout(gtx)
evt.Frame(ops)
}
}
}()
go func() {
for {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
conf := config.DefaultConfig()
configFiles := getConfigFiles(ctx)
for _, f := range configFiles {
logger.Info(ctx, "loading or creating configuration file", logger.F("filename", f))
if err := config.LoadOrCreate(ctx, f, conf, config.DefaultTransforms...); err != nil {
logger.Error(ctx, "could not load configuration file", logger.CapturedE(errors.WithStack(err)))
continue
}
break
}
cert, err := tls.X509KeyPair(conf.HTTPS.Cert, conf.HTTPS.Key)
if err != nil {
logger.Fatal(ctx, "could not parse x509 certificate", logger.CapturedE(errors.WithStack(err)))
}
server := server.New(
browser,
server.WithInstanceID(conf.InstanceID),
server.WithAppsEnabled(conf.Apps.Enabled),
server.WithDefaultApp(conf.Apps.DefaultApp),
server.WithApps(arcast.DefaultApps...),
server.WithTLSCertificate(&cert),
server.WithAddress(conf.HTTP.Address),
server.WithTLSAddress(conf.HTTPS.Address),
server.WithAllowedOrigins(conf.AllowedOrigins...),
)
if err := server.Start(); err != nil {
logger.Fatal(ctx, "could not start server", logger.CapturedE(errors.WithStack(err)))
}
defer func() {
if err := server.Stop(); err != nil {
logger.Error(ctx, "could not stop server", logger.CapturedE(errors.WithStack(err)))
}
}()
if err := server.Wait(); err != nil {
logger.Error(ctx, "could not wait for server", logger.CapturedE(errors.WithStack(err)))
}
}
}()
app.Main()
}
func getConfigFiles(ctx context.Context) []string {
configFiles := make([]string, 0)
sharedStorageConfigFile := filepath.Join("/storage/emulated/0/Android/data", packageName, "files/config.json")
configFiles = append(configFiles, sharedStorageConfigFile)
dataDir, err := app.DataDir()
if err != nil {
logger.Error(ctx, "could not retrieve app data dir", logger.CapturedE(errors.WithStack(err)))
} else {
appDataConfigFile := filepath.Join(dataDir, "config.json")
configFiles = append(configFiles, appDataConfigFile)
}
return configFiles
}

View File

@ -3,3 +3,5 @@
- [Configuration](./configuration.md)
- [API HTTP](./http-api.md)
- [mDNS](./mdns.md)
- [Installation](./installation.md)
- [Usage](./usage.md)

View File

@ -1,3 +1,9 @@
- [Configuration](#configuration)
- [Personnalisation de l'apparence](#personnalisation-de-lapparence)
- [Exemple](#exemple)
- [index.gohtml exemple](#indexgohtml-exemple)
- [Configuration arcast-player](#configuration-arcast-player)
# Configuration
Le server Arcast utilise un fichier de configuration permettant de personnaliser son comportement.
@ -52,8 +58,114 @@ Voici un exemple commenté du fichier de configuration:
}
```
## Personnalisation
## Personnalisation de l'apparence
Il est possible de personnaliser la page d'accueil du player Arcast en créant des fichiers dans le répertoire définit par l'attribut de configuration `http.customDir`.
Le contenu de ce répertoire doit répliquer l'arborescence embarquée par défaut (voir https://forge.cadoles.com/arcad/arcast/src/branch/develop/pkg/server/embed). Chaque fichier présent remplacera celui embarqué par défaut.
### Exemple
Nous voulons ajouter une image, et du texte à la page d'accueil, étant sur une ubuntu nous allons à l'emplacement : `${HOME}/.config/arcast-player/`
Soit :
```Shell
${HOME}/.config/arcast-player/
├── config.json
└── custom
```
Nous avons une image **logo.png**, un fichier css pour l'apparence **exemple.css**, et un template **index.gohtml** dans le dossier `_templates`, contenant le texte à afficher, et sa position dans la fenêtre.
Soit :
```Shell
${HOME}/.config/arcast-player/
├── config.json
└── custom
├── exemple.css
├── logo.png
└── _templates
└── index.gohtml
```
Une fois les fichiers dûments remplis, il suffit de lancer, ou re-lancer arcast-player pour voir le résultat.
#### index.gohtml exemple
```go
{{ define "message" }}
<h1 style="margin-top: 20px" class="text-centered">Bienvenue chez moi !</h1>
<hr style="margin: 20px 0 20px 0" />
<div style="margin: 20px 0 20px 0">
<p>Pensez à vous essuyer les pieds</p>
<ul>
<li>
<b style="width: 33%; display: inline-block">Pour la bière:</b>
<code>Le frigo est à droite</code>
</li>
<li>
<b style="width: 33%; display: inline-block">Pour le barbecue</b>
<code>Porte fenêtre de gauche, puis à droite ce trouve votre bonheur</code>
</li>
</ul>
<hr style="margin: 20px 0 20px 0" />
</div>
{{ end }}
{{ define "head" }}
<link rel="stylesheet" href="exemple.css" />
{{ end }}
{{ define "index" }}
{{ template "base" . }}
{{ end }}
```
Exemple de rendu avec logo cadoles.
![exemple](./resources/arcast-exemple.png)
## Configuration arcast-player
Comme constaté lors de l'affichage de l'aide pour `arcast-player run -help` il est possible d'utiliser les flags chrome pour paramétrer plus finement l'affichage.
Liens pour une liste des flags disponible à destination de chrome : [liens falgs chrome](https://peter.sh/experiments/chromium-command-line-switches/)
rappel :
```Shell
[computer@user ~]$ arcast-player run -help
NAME:
arcast run
USAGE:
arcast run [command options] [arguments...]
OPTIONS:
--config value (default: "/home/panda/.config/arcast-player/config.json") [$ARCAST_DESKTOP_CONFIG]
--additional-chrome-arg value [ --additional-chrome-arg value ] (default: "incognito") [$ARCAST_DESKTOP_ADDITIONAL_CHROME_ARGS]
--instance-id value [$ARCAST_DESKTOP_INSTANCE_ID]
--address value (default: ":") [$ARCAST_DESKTOP_ADDRESS]
--https-address value (default: ":") [$ARCAST_DESKTOP_HTTPS_ADDRESS]
--window-height value (default: 0) [$ARCAST_DESKTOP_WINDOW_HEIGHT]
--apps (default: false) [$ARCAST_DESKTOP_APPS]
--window-width value (default: 0) [$ARCAST_DESKTOP_WINDOW_WIDTH]
--allowed-origins value [ --allowed-origins value ] [$ARCAST_DESKTOP_ALLOWED_ORIGINS]
--custom-files-dir value [$ARCAST_DESKTOP_CUSTOM_FILES_DIR]
--dummy-browser (default: false) [$ARCAST_DESKTOP_DUMMY_BROWSER]
--help, -h show help
```
Exemple pour lancer chrome en ligne de commande avec le mode kiosk.
Deux possibilités :
```Shell
arcast-player run --additional-chrome-arg incognito --additional-chrome-arg kiosk
```
Il est aussi possible d'utiliser une variable d'environnement comme indiqué dans l'aide.
```Shell
ARCAST_DESKTOP_ADDITIONAL_CHROME_ARGS="incognito,kiosk" arcast-player run
```

68
doc/installation.md Normal file
View File

@ -0,0 +1,68 @@
- [Installation](#installation)
- [Android](#android)
- [Arcast-player \& client](#arcast-player--client)
- [Ubuntu/debian](#ubuntudebian)
- [Ubuntu](#ubuntu)
- [manjaro](#manjaro)
# Installation
Les paquets sont actuellement générés, et fonctionnels pour :
architecture :
- amd64
- arm64
OS :
- linux
- .apk
- .deb
- tar.gz
- android
- .apk
Leurs téléchargements pour les versions linux sont disponibles sur : [arcast-cadoles](https://forge.cadoles.com/arcad/arcast/releases)
**arcast-client**: permet d'envoyer des flux sur les players
**arcast-player**: permet l'affichage
## Android
L'App android est déployée sur [https://fdroid.cadol.es/repo/](https://fdroid.cadol.es/repo/)
Pour ajouter ce repo utilisez [F-droid](https://f-droid.org/fr/). (paramètre/depôt cliquer sur **+**)
Une fois installé, ouvrir f-droid, Arcast Player apparaîtra dans les nouveautées.
## Arcast-player & client
Télécharger sur la page des versions celle qui correspond à votre architecture, puis installer le paquet.
### Ubuntu/debian
`dpkg -i paquet.deb`
### Ubuntu
`apt install monpaquet.deb`
### manjaro
Il n'y a pas de pkg.tar.zst, il va falloir le construire. Pour cela utiliser debtap.
```Shell
# Installation debtap
sudo pacman -S debtap
# Initialisation debtap
sudo debtap -u
# construction du paquet pour Arch Linux
sudo debtap nom_du_paquet.deb
# Installation du nouveau paquet
sudo pacman -U nom_du_paquet_convertis.pkg.tar.zst
```
Note : Il y a quelque différence, notamment l'absence d'icone de lancement pour l'application.

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

136
doc/usage.md Normal file
View File

@ -0,0 +1,136 @@
- [Usage](#usage)
- [Linux](#linux)
- [Arcast-player en ligne de commande](#arcast-player-en-ligne-de-commande)
- [Kiosk mode](#kiosk-mode)
- [Arcast-client en ligne de commande](#arcast-client-en-ligne-de-commande)
- [Démarrer un cast](#démarrer-un-cast)
- [Scan](#scan)
- [Status](#status)
- [Reset](#reset)
- [Arcast-player affichage](#arcast-player-affichage)
# Usage
## Linux
Vous pouvez lancer arcast grâce à son icône depuis l'interface graphique. Si vous souhaitez avoir un mode fullscreen/kiosk il suffit d'effectuer un clic droit sur l'icône de l'application et de choisir le mode sus-mentionné.
### Arcast-player en ligne de commande
Pour afficher les commandes disponibles :
`arcast-player -help`
pour lancer arcast-player :
```Shell
# Lancer arcast-player
arcast-player run
# afficher les options disponible pour lancer arcast
arcast-player run -help
```
#### Kiosk mode
Pour lancer arcast-player en mode kiosk via la ligne de commande :
```Shell
arcast-player run --additional-chrome-arg incognito --additional-chrome-arg kiosk
```
Il est aussi possible d'utiliser une variable d'environnement.
```Shell
ARCAST_DESKTOP_ADDITIONAL_CHROME_ARGS="incognito,kiosk" arcast-player run
```
Liste des command pour chrome, permet d'avoir les informations nécessaire sur les flags disponible au lancement du cast. [link](https://peter.sh/experiments/chromium-command-line-switches/)
### Arcast-client en ligne de commande
Afficher les commandes disponibles:
`arcast-client -help`
Il y a quatre commandes disponibles hors help :
- cast
- reset
- scan
- status
- help
Chacune peut prendre des options particulières, pour les consulter `arcast-client [commande] -help`
#### Démarrer un cast
Effectuer un scan pour avoir les informations du client ciblé puis lancer la commande : `arcast-client cast --player-address x.x.x.x:port https://macible`
exemple :
```Shell
user@localhost$ arcast-client cast --player-address 192.168.10.197:45555 https://www.cadoles.com
```
#### Scan
Vous pouvez scanner le réseau actuel pour détecter tous les **arcast-player** en route.
```Shell
user@localhost$ arcast-client scan
+-----------------------+-----------------------------------+-------+
| ID | IPS | PORT |
+-----------------------+-----------------------------------+-------+
| 90ZiA_cZfHDvm6_XRY0uY | ["192.168.10.101","192.168.1.1... | 45555 |
| P5UCrO16snObXr87zlPYa | ["192.168.10.197"] | 45555 |
+-----------------------+-----------------------------------+-------+
```
#### Status
De même, il est possible d'afficher les arcast-player utilisés, et afficher ce qui est casté.
```Shell
user@localhost$ arcast-client status
+-----------------------+----------------------+---------+-------------------+--------------------------+
| ID | ADDRESS | STATUS | TITLE | URL |
+-----------------------+----------------------+---------+-------------------+--------------------------+
| 90ZiA_cZfHDvm6_XRY0uY | 192.168.10.101:45555 | casting | Cadoles - Accueil | https://www.cadoles.com/ |
| Njv7ksbvjYnCAa-WPALDI | 192.168.1.240:40931 | casting | Cadoles - Accueil | https://www.cadoles.com/ |
+-----------------------+----------------------+---------+-------------------+--------------------------+
```
#### Reset
Vous pouvez stopper tous les castes en cours.
```Shell
user@localhost$ arcast-client reset
+-----------------------+----------------------+--------+-----------------+-------------------------+
| ID | ADDRESS | STATUS | TITLE | URL |
+-----------------------+----------------------+--------+-----------------+-------------------------+
| 90ZiA_cZfHDvm6_XRY0uY | 192.168.10.101:45555 | idle | Ready to cast ! | http://localhost:45555/ |
| P5UCrO16snObXr87zlPYa | 192.168.10.197:45555 | idle | Ready to cast ! | http://localhost:45555/ |
```
## Arcast-player affichage
Rappel, pour lancer un player : `arcast-player run`
Vous avez démarré un player, une fenêtre c'est ouverte comme suivant :
![image-arcast-player](./resources/arcast-player-run.png)
Dans les zones **Address** et **Apps** vous avez les IP sur lesquelles le cast est disponible.
Depuis votre poste, ou un autre entrer l'adresse qui correspond à votre réseau et qui ce trouve sous **Apps**.
Accepter le risk, (advanced/accept the risk and continue). Vous aurez la même page, cliquer sur l'adresse dans **Apps** qui correspond.
![image-arcast-player](./resources/arcast-player-webpage.png)
Vous pourrez depuis cette interface :
1. Soit partager votre écran, pour cela cliquer sur **Screen sharing**, puis choississez ce que vous voulez partager.
2. Soit entrer une adresse web, et lancer un cast de la page choisit
3. Soit désactiver un cast en cliquant sur reset

12
go.mod
View File

@ -3,9 +3,7 @@ module forge.cadoles.com/arcad/arcast
go 1.21.4
require (
gioui.org v0.4.1
github.com/dschmidt/go-layerfs v0.1.0
github.com/gioui-plugins/gio-plugins v0.0.0-20240323070753-3331d8c2df5d
github.com/go-chi/cors v1.2.1
github.com/gorilla/websocket v1.5.1
github.com/grandcat/zeroconf v1.0.1-0.20230119201135-e4f60f8407b1
@ -13,21 +11,17 @@ require (
github.com/pkg/errors v0.9.1
github.com/wlynxg/anet v0.0.1
github.com/zserge/lorca v0.1.10
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f
)
require (
cdr.dev/slog v1.6.1 // indirect
gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7 // indirect
gioui.org/shader v1.0.8 // indirect
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/charmbracelet/lipgloss v0.7.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-text/typesetting v0.0.0-20230803102845-24e03d8b5372 // indirect
github.com/inkeliz/go_inkwasm v0.0.0-20220912074516-049d3472c98a // indirect
github.com/jedib0t/go-pretty/v6 v6.4.9 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
@ -42,12 +36,8 @@ require (
go.opentelemetry.io/otel v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 // indirect
golang.org/x/exp/shiny v0.0.0-20220921164117-439092de6870 // indirect
golang.org/x/image v0.5.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.16.1 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
gopkg.in/go-playground/validator.v9 v9.29.1 // indirect

55
go.sum
View File

@ -8,19 +8,9 @@ cloud.google.com/go/logging v1.7.0 h1:CJYxlNNNNAMkHp9em/YEXcfJg+rPDg7YfwoRpMU+t5
cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M=
cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI=
cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY=
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA=
gioui.org v0.4.1 h1:sCTw5Fexg0xg9CxYmbrkKtHXcobf0JMbl5XpF2TC/zc=
gioui.org v0.4.1/go.mod h1:2atiYR4upH71/6ehnh6XsUELa7JZOrOHHNMDxGBZF0Q=
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7 h1:tNJdnP5CgM39PRc+KWmBRRYX/zJ+rd5XaYxY5d5veqA=
gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI=
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo=
github.com/Bornholm/lorca v0.0.0-20240121134933-d5e83569cb4c h1:xG9xSpEqZYOvd1Bvx/36i3RBTA17d7XnuvoMIG+/ry8=
github.com/Bornholm/lorca v0.0.0-20240121134933-d5e83569cb4c/go.mod h1:TUOtEogaMwy0b+p9e4NxZC1jbPRUaNaEw5DnjQF//F8=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
@ -34,8 +24,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dschmidt/go-layerfs v0.1.0 h1:jE6aHDfjNzS/31DS48th6EkmELwTa1Uf+aO4jRkBs3U=
github.com/dschmidt/go-layerfs v0.1.0/go.mod h1:m62aff0hn23Q/tQBRiNSeLD7EUuimDvsuCvCpzBr3Gw=
github.com/gioui-plugins/gio-plugins v0.0.0-20240323070753-3331d8c2df5d h1:8b7owUJ8sNmgqEk+1d7ylr3TCH3vliCvY/6ycfize8o=
github.com/gioui-plugins/gio-plugins v0.0.0-20240323070753-3331d8c2df5d/go.mod h1:3XVleuCdPpdajFL+ASh2wmXZNskitXQQ4jhVss0VHZg=
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
@ -48,10 +36,6 @@ github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-text/typesetting v0.0.0-20230803102845-24e03d8b5372 h1:FQivqchis6bE2/9uF70M2gmmLpe82esEm2QadL0TEJo=
github.com/go-text/typesetting v0.0.0-20230803102845-24e03d8b5372/go.mod h1:evDBbvNR/KaVFZ2ZlDSOWWXIUKq0wCOEtzLxRM8SG3k=
github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22 h1:LBQTFxP2MfsyEDqSKmUBZaDuDHN1vpqDyOZjcqS7MYI=
github.com/go-text/typesetting-utils v0.0.0-20230616150549-2a7df14b6a22/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@ -60,8 +44,6 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grandcat/zeroconf v1.0.1-0.20230119201135-e4f60f8407b1 h1:cNb52t5fkWv8ZiicKWnc2eZnhsCCoH7WmRBMIbMp04Q=
github.com/grandcat/zeroconf v1.0.1-0.20230119201135-e4f60f8407b1/go.mod h1:I6CSXU4zCGL08JOk9NbcT0ofAgnIkS/fVXbYzfSoDic=
github.com/inkeliz/go_inkwasm v0.0.0-20220912074516-049d3472c98a h1:uZklbtdSPrDL/d1EUKd9s8a0Byla2TT01Wg/GZ4xj0w=
github.com/inkeliz/go_inkwasm v0.0.0-20220912074516-049d3472c98a/go.mod h1:LPI3Qojj7OgTyc2R4RPB6BuMSgjoOXCObwnDzz1SOVk=
github.com/jaevor/go-nanoid v1.3.0 h1:nD+iepesZS6pr3uOVf20vR9GdGgJW1HPaR46gtrxzkg=
github.com/jaevor/go-nanoid v1.3.0/go.mod h1:SI+jFaPuddYkqkVQoNGHs81navCtH388TcrH0RqFKgY=
github.com/jedib0t/go-pretty/v6 v6.4.9 h1:vZ6bjGg2eBSrJn365qlxGcaWu09Id+LHtrfDWlB2Usc=
@ -109,7 +91,6 @@ github.com/wlynxg/anet v0.0.1 h1:VbkEEgHxPSrRQSiyRd0pmrbcEQAEU2TTb8fb4DmSYoQ=
github.com/wlynxg/anet v0.0.1/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
gitlab.com/wpetit/goweb v0.0.0-20231215190137-4a8add1d3d07 h1:0V95X1cBpdj5zyOe6oGtn/BQHlRpV8WlL3eTs3jaxiA=
gitlab.com/wpetit/goweb v0.0.0-20231215190137-4a8add1d3d07/go.mod h1:Nfr7aZPiSN6biFumhiHbh9k8A3rKQRzR+o0bVtv78UY=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
@ -121,59 +102,59 @@ go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 h1:sBdrWpxhGDdTAYNqbgBLAR+ULAPPhfgncLr1X0lyWtg=
golang.org/x/exp v0.0.0-20221012211006-4de253d81b95/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp/shiny v0.0.0-20220921164117-439092de6870 h1:GjCs9zNN8fojJskeK7QiiVecCaMk0dfGTyL6IUcmp0o=
golang.org/x/exp/shiny v0.0.0-20220921164117-439092de6870/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8=
golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f h1:kgfVkAEEQXXQ0qc6dH7n6y37NAYmTFmz0YRwrRjgxKw=
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e h1:xIXmWJ303kJCuogpj0bHq+dcjcZHU+XFyc1I0Yl9cRg=

86
pkg/android/binding.go Normal file
View File

@ -0,0 +1,86 @@
package android
import (
"context"
"crypto/tls"
"net"
"path/filepath"
"forge.cadoles.com/arcad/arcast"
"forge.cadoles.com/arcad/arcast/pkg/browser/proxy"
"forge.cadoles.com/arcad/arcast/pkg/config"
"forge.cadoles.com/arcad/arcast/pkg/server"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
var (
browser = proxy.NewBrowser()
)
func SetBridge(bridge Bridge) {
browser.SetLoadURL(bridge.LoadURL)
browser.SetGetTitle(bridge.GetTitle)
browser.SetGetURL(bridge.GetURL)
}
func StartServer(dataDir string) string {
ctx := context.Background()
conf := config.DefaultConfig()
filename := filepath.Join(dataDir, "config.json")
logger.Info(ctx, "loading or creating configuration file", logger.F("filename", filename))
if err := config.LoadOrCreate(ctx, filename, conf, config.DefaultTransforms...); err != nil {
logger.Error(ctx, "could not load configuration file", logger.CapturedE(errors.WithStack(err)))
}
go func() {
for {
runServer(ctx, conf)
}
}()
_, port, err := net.SplitHostPort(conf.HTTP.Address)
if err != nil {
panic(errors.Wrap(err, "could not parse server listening address"))
}
return port
}
func runServer(ctx context.Context, conf *config.Config) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
cert, err := tls.X509KeyPair(conf.HTTPS.Cert, conf.HTTPS.Key)
if err != nil {
logger.Fatal(ctx, "could not parse x509 certificate", logger.CapturedE(errors.WithStack(err)))
}
server := server.New(
browser,
server.WithInstanceID(conf.InstanceID),
server.WithAppsEnabled(conf.Apps.Enabled),
server.WithDefaultApp(conf.Apps.DefaultApp),
server.WithApps(arcast.DefaultApps...),
server.WithTLSCertificate(&cert),
server.WithAddress(conf.HTTP.Address),
server.WithTLSAddress(conf.HTTPS.Address),
server.WithAllowedOrigins(conf.AllowedOrigins...),
)
if err := server.Start(); err != nil {
logger.Fatal(ctx, "could not start server", logger.CapturedE(errors.WithStack(err)))
}
defer func() {
if err := server.Stop(); err != nil {
logger.Error(ctx, "could not stop server", logger.CapturedE(errors.WithStack(err)))
}
}()
if err := server.Wait(); err != nil {
logger.Error(ctx, "could not wait for server", logger.CapturedE(errors.WithStack(err)))
}
}

11
pkg/android/bridge.go Normal file
View File

@ -0,0 +1,11 @@
package android
import (
_ "golang.org/x/mobile/bind"
)
type Bridge interface {
LoadURL(url string)
GetTitle() string
GetURL() string
}

View File

@ -1,118 +0,0 @@
package gioui
import (
"context"
"sync/atomic"
"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 *atomic.Value
changed *atomic.Bool
status *atomic.Value
title *atomic.Value
}
func (b *Browser) Layout(gtx layout.Context) layout.Dimensions {
events := gtx.Events(&b.tag)
for _, evt := range events {
switch ev := evt.(type) {
case webviewer.TitleEvent:
b.title.Store(ev.Title)
case webviewer.NavigationEvent:
b.url.Store(ev.URL)
}
}
ctx := context.Background()
logger.Debug(ctx, "drawing")
webviewer.WebViewOp{Tag: &b.tag}.Push(gtx.Ops)
webviewer.OffsetOp{
Point: f32.Point{
X: 0,
Y: 0,
},
}.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.CompareAndSwap(true, false) {
url := b.url.Load().(string)
logger.Debug(ctx, "url changed", logger.F("url", url))
webviewer.NavigateOp{URL: url}.Add(gtx.Ops)
}
return layout.Dimensions{Size: gtx.Constraints.Max}
}
// Load implements browser.Browser.
func (b *Browser) Load(url string) error {
b.url.Store(url)
b.changed.Store(true)
b.status.Store(browser.StatusCasting)
b.window.Invalidate()
return nil
}
// Status implements browser.Browser.
func (b *Browser) Status() (browser.Status, error) {
return b.status.Load().(browser.Status), nil
}
// Title implements browser.Browser.
func (b *Browser) Title() (string, error) {
return b.title.Load().(string), nil
}
// URL implements browser.Browser.
func (b *Browser) URL() (string, error) {
return b.url.Load().(string), nil
}
// Reset implements browser.Browser.
func (b *Browser) Reset(url string) error {
b.url.Store(url)
b.changed.Store(true)
b.status.Store(browser.StatusIdle)
b.window.Invalidate()
return nil
}
func NewBrowser(window *app.Window) *Browser {
b := &Browser{
window: window,
url: &atomic.Value{},
changed: &atomic.Bool{},
status: &atomic.Value{},
title: &atomic.Value{},
}
b.url.Store("")
b.title.Store("")
b.changed.Store(false)
b.status.Store(browser.StatusIdle)
return b
}
var _ browser.Browser = &Browser{}

View File

@ -0,0 +1,110 @@
package proxy
import (
"sync"
"forge.cadoles.com/arcad/arcast/pkg/browser"
"github.com/pkg/errors"
)
var (
ErrNotInitialized = errors.New("not initialized")
)
type Browser struct {
loadURL func(url string)
getURL func() string
getTitle func() string
status browser.Status
mutex sync.RWMutex
}
// Load implements browser.Browser.
func (b *Browser) Load(url string) error {
b.mutex.Lock()
defer b.mutex.Unlock()
if b.loadURL == nil {
return errors.WithStack(ErrNotInitialized)
}
b.loadURL(url)
b.status = browser.StatusCasting
return nil
}
// Reset implements browser.Browser.
func (b *Browser) Reset(url string) error {
b.mutex.Lock()
defer b.mutex.Unlock()
if b.loadURL == nil {
return errors.WithStack(ErrNotInitialized)
}
b.loadURL(url)
b.status = browser.StatusIdle
return nil
}
// Status implements browser.Browser.
func (b *Browser) Status() (browser.Status, error) {
b.mutex.RLock()
defer b.mutex.RUnlock()
return b.status, nil
}
// Title implements browser.Browser.
func (b *Browser) Title() (string, error) {
b.mutex.RLock()
defer b.mutex.RUnlock()
if b.getTitle == nil {
return "", errors.WithStack(ErrNotInitialized)
}
return b.getTitle(), nil
}
// URL implements browser.Browser.
func (b *Browser) URL() (string, error) {
b.mutex.RLock()
defer b.mutex.RUnlock()
if b.getURL == nil {
return "", errors.WithStack(ErrNotInitialized)
}
return b.getURL(), nil
}
func (b *Browser) SetLoadURL(fn func(url string)) {
b.mutex.Lock()
defer b.mutex.Unlock()
b.loadURL = fn
}
func (b *Browser) SetGetTitle(fn func() string) {
b.mutex.Lock()
defer b.mutex.Unlock()
b.getTitle = fn
}
func (b *Browser) SetGetURL(fn func() string) {
b.mutex.Lock()
defer b.mutex.Unlock()
b.getURL = fn
}
func NewBrowser() *Browser {
return &Browser{}
}
var _ browser.Browser = &Browser{}