Skip to content
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

Reorganize sources & introduce WASM SDK #130

Merged
merged 132 commits into from
Nov 11, 2023
Merged
Changes from 1 commit
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
9d7d143
Add support for multiple unique sessions
Zubnix Apr 18, 2023
1fadb2d
Update program args to support single static session id
Zubnix Apr 18, 2023
52066aa
Begin implementing per proxy session i/o
Zubnix Apr 21, 2023
a47aeb0
make multiple proxy sessions work
Zubnix Apr 24, 2023
be362bb
Make cors work & fix tests
Zubnix Apr 24, 2023
1586f56
make closing remote sessions work properly
Zubnix Apr 25, 2023
8c65932
be able to launch child apps based on http url
Zubnix Apr 30, 2023
5742c85
use a signaling connection per launched app
Zubnix May 16, 2023
3d96b43
Rework proxy app launching
Zubnix May 24, 2023
7e3b232
rename client signaling to app context
Zubnix May 25, 2023
ff2da7b
begin separating compositor-proxy as CLI and as lib
Zubnix May 27, 2023
f9a278d
begin separating compositor-proxy as CLI and as lib
Zubnix May 30, 2023
4c906fb
begin separating compositor-proxy as CLI and as lib (more wip)
Zubnix May 31, 2023
f877355
rub some tailwindcss on the demo compositor
Zubnix Jun 1, 2023
594bd37
rub some more tailwindcss on the demo compositor (wip)
Zubnix Jun 8, 2023
d57369c
rub some more tailwindcss on the demo compositor (wip)
Zubnix Jun 8, 2023
4251927
Fix socket reconnection bug when proxy instances is restarted
Zubnix Jun 8, 2023
53f1ce7
Update deps
Zubnix Jun 12, 2023
1ab708f
Update cosmetics
Zubnix Jun 12, 2023
9d798ca
Update yarn from v1 to v3
Zubnix Jun 12, 2023
dd8de93
Update yarn from v1 to v3
Zubnix Jun 12, 2023
6b8225f
migrate (nearly) all interaction to node websockets
Zubnix Jun 18, 2023
32cabf0
migrate (nearly) all interaction to node websockets
Zubnix Jun 20, 2023
ed48a13
migrate (nearly) all interaction to node websockets
Zubnix Jun 20, 2023
f635021
migrate (nearly) all interaction to node websockets
Zubnix Jun 20, 2023
082b874
add some basic auth and move some code around
Zubnix Jun 22, 2023
1e1c2ba
Begin updating docs
Zubnix Jun 22, 2023
a3aaaaf
updating docs
Zubnix Jun 22, 2023
6883bdf
doc update & chrome webgl fix
Zubnix Jun 27, 2023
e141d48
use a separate app mapping file
Zubnix Jun 27, 2023
6e4494a
Immediately adjust feedback timer ticks
Zubnix Jun 29, 2023
aa74886
Make sure we can decode high level h264 on the client
Zubnix Jun 29, 2023
2cd03f2
Fix XWayland apps not being able to launch as first app
Zubnix Jun 29, 2023
b4c611b
start adding webapp demos
Zubnix Aug 31, 2023
0420517
Start restructuring project
Zubnix Sep 13, 2023
19ae07d
update gitignore
Zubnix Sep 13, 2023
0251464
more yarn workspace configuration
Zubnix Sep 13, 2023
710eda8
more wip
Zubnix Sep 14, 2023
d168c1c
more wip
Zubnix Sep 14, 2023
dc42335
wip
Zubnix Sep 15, 2023
e173681
add sdk to monorepo
Zubnix Sep 15, 2023
a135ad5
move stuff around
Zubnix Sep 15, 2023
e5f25ff
wip
Zubnix Sep 15, 2023
3376b20
wip
Zubnix Sep 16, 2023
3bb4b2a
wip
Zubnix Sep 17, 2023
9ea6c2c
add gitignores
Zubnix Sep 18, 2023
8ad46c4
make sdk work on mac
Zubnix Sep 19, 2023
de14706
make shell deps work
Zubnix Sep 19, 2023
1f3972c
make shell work
Zubnix Sep 19, 2023
1bfa799
make shell work
Zubnix Sep 19, 2023
3dfd18f
fix xtsb build, fix compositor wasm libs
Zubnix Sep 19, 2023
2ca3316
Fix shell worker resolution
Zubnix Sep 19, 2023
e962a1d
Fix shell stuff
Zubnix Sep 19, 2023
92cf76f
more wip
Zubnix Sep 20, 2023
327d61a
more wip
Zubnix Sep 20, 2023
8a97af7
more wip
Zubnix Sep 20, 2023
b84b011
more wip
Zubnix Sep 22, 2023
faa98ce
Make web apps work
Zubnix Sep 23, 2023
eec89ab
Make web apps work
Zubnix Sep 25, 2023
c601160
more wip
Zubnix Sep 25, 2023
7236758
more wip
Zubnix Sep 26, 2023
5178d85
add ffmpeg h264 decoder
Zubnix Sep 26, 2023
d16378e
fix sdk build on linux
Zubnix Sep 27, 2023
943c7a8
streamline webapp & remoteapp launcher
Zubnix Sep 27, 2023
aad5c16
add starter jekyll site
Zubnix Sep 27, 2023
33cbc20
remove ffmpeg git repo
Zubnix Sep 27, 2023
6a433b6
update site config
Zubnix Sep 27, 2023
dc64990
docs site fiddling
Zubnix Sep 28, 2023
6e0979b
update site config
Zubnix Sep 28, 2023
68bff56
update shell
Zubnix Sep 28, 2023
f093e6d
update shell
Zubnix Sep 30, 2023
aa47f07
split out compositor-proxy into lib & cli package
Zubnix Oct 1, 2023
86cb809
more wip
Zubnix Oct 3, 2023
77f28fd
more wip
Zubnix Oct 3, 2023
efe4cbc
more wip
Zubnix Oct 4, 2023
1499500
more wip
Zubnix Oct 4, 2023
52c7f01
begin adding docs site layout
Zubnix Oct 4, 2023
07f6a9e
update gitignore
Zubnix Oct 4, 2023
50f5399
more wip
Zubnix Oct 5, 2023
2a29be2
more wip
Zubnix Oct 5, 2023
24234f0
more wip
Zubnix Oct 5, 2023
7877401
more wip
Zubnix Oct 6, 2023
eaa467e
more wip
Zubnix Oct 6, 2023
03c08a7
more wip
Zubnix Oct 6, 2023
79edc87
more wip
Zubnix Oct 6, 2023
c6ee002
more wip
Zubnix Oct 6, 2023
bab96e6
more wip
Zubnix Oct 7, 2023
5c384ad
more wip
Zubnix Oct 10, 2023
1f7fbe5
more wip
Zubnix Oct 10, 2023
6911592
more wip
Zubnix Oct 10, 2023
8445d6b
more wip
Zubnix Oct 10, 2023
2201841
more wip
Zubnix Oct 11, 2023
ddec939
more wip
Zubnix Oct 11, 2023
3714025
more wip
Zubnix Oct 11, 2023
b8fd366
more wip
Zubnix Oct 11, 2023
02cb0fd
more wip
Zubnix Oct 13, 2023
0cd7e6a
more wip
Zubnix Oct 13, 2023
6cc2c8a
more wip
Zubnix Oct 13, 2023
f3f8ed6
more wip
Zubnix Oct 15, 2023
ec73f88
more wip
Zubnix Oct 16, 2023
ae3d428
more wip
Zubnix Oct 21, 2023
377095b
more wip
Zubnix Oct 22, 2023
0a71d39
more wip
Zubnix Oct 22, 2023
74a4402
more wip
Zubnix Oct 24, 2023
ba39d7a
more wip
Zubnix Oct 24, 2023
d885a09
more wip
Zubnix Nov 11, 2023
2f2eecb
more wip
Zubnix Oct 25, 2023
60bcc34
more wip
Zubnix Oct 25, 2023
b6f4332
more wip
Zubnix Oct 25, 2023
05ffbb4
more wip
Zubnix Oct 26, 2023
2de66d0
more wip
Zubnix Oct 27, 2023
71da5ee
more wip
Zubnix Oct 27, 2023
3e1696a
more wip
Zubnix Oct 31, 2023
eb7952f
more wip
Zubnix Oct 31, 2023
fe8b98d
more wip
Zubnix Oct 31, 2023
4dc0f06
more wip
Zubnix Oct 31, 2023
cd5a8f0
more wip
Zubnix Nov 1, 2023
e2e0972
more wip
Zubnix Nov 1, 2023
fbf9db7
more wip
Zubnix Nov 2, 2023
ad71c85
more wip
Zubnix Nov 2, 2023
53f7853
more wip
Zubnix Nov 2, 2023
0cc8f0b
more wip
Zubnix Nov 2, 2023
8fb3399
more wip
Zubnix Nov 3, 2023
4f851ae
more wip
Zubnix Nov 4, 2023
a8940d5
more wip
Zubnix Nov 4, 2023
ccd146b
more wip
Zubnix Nov 5, 2023
8d3ca26
more wip
Zubnix Nov 6, 2023
f4e2132
more wip
Zubnix Nov 6, 2023
3c7b92e
more wip
Zubnix Nov 7, 2023
a760722
more wip
Zubnix Nov 8, 2023
62e4f2e
Create CNAME
Zubnix Nov 11, 2023
b0e6ca1
more wip
Zubnix Nov 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rework proxy app launching
Zubnix committed Nov 11, 2023
commit 3d96b432cd023b4d1f6e86a15323dd1947a3e524
2 changes: 1 addition & 1 deletion compositor-module/demo-compositor/index.html
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Greenfield Demo Compositor</title>
<title>Greenfield</title>
<style>
#container {
display: flex;
12 changes: 6 additions & 6 deletions compositor-module/demo-compositor/src/App.tsx
Original file line number Diff line number Diff line change
@@ -5,9 +5,9 @@ import {
CompositorClient,
CompositorSession,
createCompositorSession,
createConnector,
createAppLauncher,
initWasm,
RemoteCompositorConnector,
AppLauncher,
WebCompositorConnector,
} from '../../src'
import { ClientProps } from './Client'
@@ -22,7 +22,7 @@ const windows = new Signal([] as WindowProps[])

function Controls(props: {
session: CompositorSession
proxyConnector: RemoteCompositorConnector
appLauncher: AppLauncher
webConnector: WebCompositorConnector
}) {
return (
@@ -63,8 +63,8 @@ export async function main() {
const id = Array.from(arr, (v) => v.toString(16).padStart(2, '0')).join('')

const session = await createCompositorSession(id)
const proxyConnector = createConnector(session, 'remote')
const webConnector = createConnector(session, 'web')
const appLauncher = createAppLauncher(session, 'remote')
const webConnector = createAppLauncher(session, 'web')

session.userShell.events.clientDestroyed = (client: CompositorClient) => {
clients.value = clients.value.filter((otherClient) => otherClient.id !== client.id)
@@ -128,7 +128,7 @@ export async function main() {
session.globals.register()

render(
<Controls session={session} proxyConnector={proxyConnector} webConnector={webConnector} />,
<Controls session={session} appLauncher={appLauncher} webConnector={webConnector} />,
elementById('controls-container'),
)
}
25 changes: 14 additions & 11 deletions compositor-module/demo-compositor/src/ProxyConnection.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { CompositorSession, RemoteClientConnectionListener } from '../../src'
import { CompositorSession, AppContext } from '../../src'
import { useState } from 'preact/compat'
import { Signal } from '@preact/signals'
import { ClientProps } from './Client'

function ConnectionStateIcon(props: { state: RemoteClientConnectionListener['state'] }) {
function ConnectionStateIcon(props: { state: AppContext['state'] }) {
switch (props.state) {
case 'open':
return <span class="app-state">🟩 </span>
case 'connecting':
return <>⌛</>
case 'closing':
case 'error':
return <>💀</>
case 'closed':
default:
return <span class="app-state">🟥 </span>
@@ -20,25 +21,27 @@ export type ProxyConnectionProps = {
session: CompositorSession
url: URL
name: string
proxyListener: RemoteClientConnectionListener
appContext: AppContext
clients: Signal<ClientProps[]>
remove: () => void
proxySessionKey: string
}

export function ProxyConnection(props: ProxyConnectionProps) {
const [connectionState, setConnectionState] = useState(props.proxyListener.state)
props.proxyListener.onConnectionStateChange = (state) => {
const [connectionState, setConnectionState] = useState(props.appContext.state)
props.appContext.onStateChange = (state) => {
setConnectionState(state)
if (state === 'terminated') {
props.remove()
}
}
props.proxyListener.onClient = (client) => {
props.appContext.onClient = (client) => {
props.clients.value = [
...props.clients.value,
{
id: client.id,
unresponsive: new Signal(false),
onClose: () => {
props.session.userShell.actions.closeClient(client)
},
onClose: props.remove,
origin: props.name,
},
]
@@ -49,7 +52,7 @@ export function ProxyConnection(props: ProxyConnectionProps) {
<ConnectionStateIcon state={connectionState} />
<span class="app-url">{props.name}</span>
<button class="app-close" onClick={props.remove}>
🗑️
</button>
</div>
)
79 changes: 51 additions & 28 deletions compositor-module/demo-compositor/src/ProxyConnector.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,92 @@
import { Signal, signal } from '@preact/signals'
import { ProxyConnection, ProxyConnectionProps } from './ProxyConnection'
import { CompositorSession, RemoteClientConnectionListener, RemoteCompositorConnector } from '../../src'
import { AppContext, AppLauncher, CompositorSession } from '../../src'
import { ClientProps } from './Client'
import { useCallback } from 'preact/compat'

const connections = signal([] as ProxyConnectionProps[])
const connectionURL = signal('localhost:8081')

function removeConnection(removedConnectionProps: ProxyConnectionProps, proxyListener: RemoteClientConnectionListener) {
function removeConnection(removedConnectionProps: ProxyConnectionProps, proxyListener: AppContext) {
proxyListener.close()
connections.value = connections.value.filter((connection) => connection !== removedConnectionProps)
}

function addConnection(
function handleNewAppContext(
appContext: AppContext,
session: CompositorSession,
compositorProxyConnector: RemoteCompositorConnector,
url: URL,
clients: Signal<ClientProps[]>,
) {
const url = new URL(connectionURL.value)
url.searchParams.append('compositorSessionId', session.compositorSessionId)

const proxyListener = compositorProxyConnector.launch(url)
const proxyConnectionProps: ProxyConnectionProps = {
session,
url,
name: connectionURL.value,
proxyListener,
name: url.href,
appContext,
remove: () => {
removeConnection(proxyConnectionProps, proxyListener)
removeConnection(proxyConnectionProps, appContext)
},
clients,
proxySessionKey: proxyListener.proxySessionKey ?? '',
proxySessionKey: appContext.key ?? '',
}

connections.value = [...connections.value, proxyConnectionProps]

proxyListener.remoteIdentityChanged = (remoteIdentity) => {
proxyConnectionProps.proxySessionKey = remoteIdentity
appContext.onKeyChanged = (key) => {
proxyConnectionProps.proxySessionKey = key
connections.value = [...connections.value]
}
}

function onInput(event: Event) {
if (event.target && event.target instanceof HTMLInputElement) {
connectionURL.value = event.target.value
}
function addConnection(
session: CompositorSession,
compositorProxyConnector: AppLauncher,
clients: Signal<ClientProps[]>,
connectionURL: string,
) {
const url = new URL(
connectionURL.startsWith('http://') || connectionURL.startsWith('https://')
? connectionURL
: `http://${connectionURL}`,
)

const appContext = compositorProxyConnector.launch(url, (childAppContext) => {
handleNewAppContext(childAppContext, session, url, clients)
})

handleNewAppContext(appContext, session, url, clients)
}

export type ProxyConnectorProps = {
session: CompositorSession
proxyConnector: RemoteCompositorConnector
appLauncher: AppLauncher
clients: Signal<ClientProps[]>
}

export function ProxyConnector(props: ProxyConnectorProps) {
const onKeyUp = (event: KeyboardEvent) => {
if (event.key === 'Enter') {
addConnection(props.session, props.proxyConnector, props.clients)
}
}
const onKeyPress = useCallback(
(event: KeyboardEvent) => {
if (
event.key === 'Enter' &&
event.target &&
event.target instanceof HTMLInputElement &&
event.target.value.trim() !== ''
) {
addConnection(props.session, props.appLauncher, props.clients, event.target.value)
event.target.value = ''
}
},
[addConnection, props],
)

return (
<div>
<label class="launch-input-label">
🖥️ <input type="text" value={connectionURL} onInput={onInput} onKeyUp={onKeyUp} />
</label>
<form
onSubmit={(ev) => {
ev.preventDefault()
}}
>
<input type="text" onKeyPress={onKeyPress} placeholder="🖥️ type a URL" name="remote" />
</form>
<div>
<ul>
{connections.value.map((connection) => (
44 changes: 28 additions & 16 deletions compositor-module/demo-compositor/src/WebAppLauncher.tsx
Original file line number Diff line number Diff line change
@@ -2,16 +2,21 @@ import { Signal } from '@preact/signals'
import { CompositorSession, WebCompositorConnector } from '../../src'
import { WebApp, WebAppProps } from './WebApp'
import { ClientProps } from './Client'
import { useCallback } from 'preact/compat'

const webAppURL = new Signal('http://localhost:9000')
const webApps = new Signal([] as WebAppProps[])

function launchWebApp(
session: CompositorSession,
webConnector: WebCompositorConnector,
clients: Signal<ClientProps[]>,
connectionURL: string,
) {
const url = new URL(webAppURL.value)
const url = new URL(
connectionURL.startsWith('http://') || connectionURL.startsWith('https://')
? connectionURL
: `http://${connectionURL}`,
)
const webAppListener = webConnector.launch(url)
const webApp: WebAppProps = { url, onClose: () => webAppListener.close(), loaded: new Signal(false) }
webApps.value = [...webApps.value, webApp]
@@ -39,29 +44,36 @@ function launchWebApp(
}
}

function onInput(event: Event) {
if (event.target && event.target instanceof HTMLInputElement) {
webAppURL.value = event.target.value
}
}

export type WebAppLauncherProps = {
session: CompositorSession
webConnector: WebCompositorConnector
clients: Signal<ClientProps[]>
}
export function WebAppLauncher(props: WebAppLauncherProps) {
const onKeyUp = (event: KeyboardEvent) => {
if (event.key === 'Enter') {
launchWebApp(props.session, props.webConnector, props.clients)
}
}
const onKeyPress = useCallback(
(event: KeyboardEvent) => {
if (
event.key === 'Enter' &&
event.target &&
event.target instanceof HTMLInputElement &&
event.target.value.trim() !== ''
) {
launchWebApp(props.session, props.webConnector, props.clients, event.target.value)
event.target.value = ''
}
},
[launchWebApp, props],
)

return (
<div>
<label class="launch-input-label">
🌐 <input type="text" name="launch" value={webAppURL} onInput={onInput} onKeyUp={onKeyUp} />
</label>
<form
onSubmit={(ev) => {
ev.preventDefault()
}}
>
<input type="text" name="launch" onKeyPress={onKeyPress} placeholder="🌐 type a URL" />
</form>
<div>
<ul>
{webApps.value.map((webApp) => (
3 changes: 2 additions & 1 deletion compositor-module/demo-compositor/vite.config.mts
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ export default defineConfig({
root: './demo-compositor',
server: {
port: 8080,
strictPort: true
strictPort: true,
},
})

1 change: 1 addition & 0 deletions compositor-module/package.json
Original file line number Diff line number Diff line change
@@ -47,6 +47,7 @@
"@types/node": "^20.1.2",
"@typescript-eslint/eslint-plugin": "^5.59.5",
"@typescript-eslint/parser": "^5.59.5",
"@vitejs/plugin-basic-ssl": "^1.0.1",
"cpy-cli": "^4.2.0",
"eslint": "^8.40.0",
"eslint-config-prettier": "^8.8.0",
28 changes: 14 additions & 14 deletions compositor-module/src/index.ts
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
// along with Greenfield. If not, see <https://www.gnu.org/licenses/>.

import { Client } from 'westfield-runtime-server'
import { RemoteConnector } from './remote/RemoteConnector'
import { RemoteAppLauncher } from './remote/RemoteAppLauncher'
import Session, { GreenfieldLogger } from './Session'
import { UserShellApi } from './UserShellApi'
import { nrmlvo } from './Xkb'
@@ -84,41 +84,41 @@ export interface ClientConnectionListener {
readonly type: CompositorConnector['type']
}

export interface RemoteClientConnectionListener extends ClientConnectionListener {
readonly state: 'closed' | 'closing' | 'connecting' | 'open'
export interface AppContext extends ClientConnectionListener {
readonly state: 'closed' | 'open' | 'connecting' | 'terminated' | 'error'
readonly type: 'remote'
readonly key?: string

remoteIdentityChanged: (remoteIdentity: string) => void
onConnectionStateChange: (state: 'closed' | 'open') => void
onKeyChanged: (key: string) => void
onStateChange: (state: Exclude<AppContext['state'], 'connecting'>) => void
onError: (error: Error) => void
}

export interface AppLauncher {
launch(url: URL, onChildAppContext: (childAppContext: AppContext) => void): AppContext
readonly type: 'remote'
}

export interface WebClientConnectionListener extends ClientConnectionListener {
readonly type: 'web'
onClose?: () => void
webAppIFrame?: HTMLIFrameElement
onNeedIFrameAttach?: (webAppIFrame: HTMLIFrameElement) => void
}

export interface RemoteCompositorConnector {
launch(url: URL, auth?: string): RemoteClientConnectionListener
readonly type: 'remote'
}

export interface WebCompositorConnector {
launch(url: URL): WebClientConnectionListener
readonly type: 'web'
}

export type CompositorConnector = RemoteCompositorConnector | WebCompositorConnector
export type CompositorConnector = AppLauncher | WebCompositorConnector

type CompositorConnectorTypeMap = {
web: WebCompositorConnector
remote: RemoteCompositorConnector
remote: AppLauncher
}

export function createConnector<T extends CompositorConnector['type']>(
export function createAppLauncher<T extends CompositorConnector['type']>(
session: CompositorSession,
type: T,
): CompositorConnectorTypeMap[T] {
@@ -127,7 +127,7 @@ export function createConnector<T extends CompositorConnector['type']>(
}
if (type === 'remote') {
// @ts-ignore
return RemoteConnector.create(session)
return RemoteAppLauncher.create(session)
} else if (type === 'web') {
// @ts-ignore
return WebAppLauncher.create(session)
Loading