wails icon indicating copy to clipboard operation
wails copied to clipboard

Feature/add support for server and hybrid

Open tmclane opened this issue 2 years ago • 46 comments

This is a first pass implementation of a Wails target type of server and hybrid.

wails build -outputType hybrid
wails build -outputType server

Both server and hybrid accept an optional options.Server argument to define the host and port on which to listen. The intent was to allow the hybrid to enable / disable the server endpoint at runtime but this is not implemented at this time.

Server

  • only enables the dev server on the specified host and port (does not open a local window)

Hybrid

  • Always opens a local desktop window
  • Enables a remote access option using the devserver functionality on the specified host/port.

Default port is : 3112

tmclane avatar Jul 25 '22 20:07 tmclane

Deploying wails with  Cloudflare Pages  Cloudflare Pages

Latest commit: f4c9976
Status: ✅  Deploy successful!
Preview URL: https://40d74f09.wails.pages.dev
Branch Preview URL: https://feature-add-support-for-serv.wails.pages.dev

View logs

@tmclane I played a bit with your feature but I can't really get it to work.

My main issue is that an app compiled with -outputType server seems to never call the OnStartup and/or OnDomReady callbacks which takes away opportunity to store the context like I am used to along with all related functionality...

m29h avatar Aug 08 '22 15:08 m29h

I'll look into that although it leads to a few questions.

  • Would you want the OnDomReady to be called each time a new client connects?
  • At what point is the OnStartup supposed to be called?

tmclane avatar Aug 08 '22 16:08 tmclane

I don't expect the server to function exactly the same as the local version since it is multi-user capable by default. Note that each connection is it's own connection and does not share state automatically either.

tmclane avatar Aug 08 '22 16:08 tmclane

For my use case of 'server' I need the same functionality of wails such as RPC and events with the only difference that the app runs in the browser and there is no dependency of the app to a desktop window Operating system framework.

Think an wails app running on a raspberry pi and the user interface operated from any browser in the local network.

I would not have any requirements on shared state between two browser apps. For my use case 99% of time there would be only a single browser connected. I guess the cleanest solution would be if a new instance of every RPC backend app object would be created on any new browser connection. This would then also start the OnXXXX callback events each time for the new instance.

The probably cleaner way would be if every wails rpc call would pass a reference to the Caller context on each RPC call. However that seems to be beyond the current way wails works.

m29h avatar Aug 08 '22 17:08 m29h

You've described my use-case as well. I'll look into getting the OnXXX events to occur.

tmclane avatar Aug 08 '22 18:08 tmclane

Thank you for testing! I'll have an update soon hopefully time permitting.

tmclane avatar Aug 10 '22 17:08 tmclane

Travis, I played around with your branch and committed my current status to m29/hfeature/add_support_for_server_and_hybrid

My main changes are enforcing the null frontend to call the OnStartup() callback and I also changed a bit the app_hybrid_server.go because the go.embed asset embedding was apparently broken.

There is a lot of duplicate/redundant code in the app_hybrid_server.go+app_dev.go+app_production.go files that could in principle be restructured given that all of them more-or-less do the same but with slightly different mechanisms.

Functionality wise I would be happy with the version on m29/hfeature/add_support_for_server_and_hybrid.

I even tested some edge-cases like browser/disconnect/reconnect and multiple paralell browser connections, and everything works within my use case.

Of course feel free to merge code from my branch into your PR.

m29h avatar Aug 14 '22 14:08 m29h

I completely agree there is a ton of redundancy in the code. I was trying to go step by step instead of a huge rewrite as the first pass at this.
I'll be happy to incorporate your change into my branch for now and then will continue to improve it over time.

I'll kee rebasing until we get it merged to main.

tmclane avatar Aug 14 '22 14:08 tmclane

I do feel the null front end will not be needed in the final version. It was just a workaround to be able to use the existing dev server code.

tmclane avatar Aug 14 '22 14:08 tmclane

@m29h Your commit has been included in this branch.

tmclane avatar Aug 15 '22 02:08 tmclane

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Sep 21 '22 02:09 stale[bot]

does this merge allow me to reuse the same (desktop) UI code on a http server? or the 'server' output is just here to help debugging?

laoshaw avatar Oct 07 '22 12:10 laoshaw

@laoshaw the idea is that the same application would be able to be accessible over the network in a remote client session. Note that it does not share any state with a local window on the desktop. Multiple webclients can connect at the same time as well but are not linked together and are basically independent. I am going to pick this up again in earnest real soon now.

tmclane avatar Dec 05 '22 21:12 tmclane

It will be rebased and then updated to match the current state of the codebase.

tmclane avatar Dec 05 '22 21:12 tmclane

Actually I was redoing this work in a new way. This may be discarded..

tmclane avatar Dec 05 '22 21:12 tmclane

This would be amazing for what I'm looking for. We have a cli tool at my work that has to be executed and authenticated locally by each user. Being able to run CLI commands in this tool locally and displaying in a browser window would be awesome. We'd like to get away from using a desktop GUI if possible and just have them launch the app and browse on localhost:port. Thanks for this work @tmclane!

alienator88 avatar Dec 05 '22 21:12 alienator88

I wasn't planning on adding authentication to the endpoint immediately. Sounds like that needs to be put on the roadmap as well.

tmclane avatar Dec 05 '22 22:12 tmclane

Oh sorry, I might've explained wrong. No auth needed from the wails side for my use case at least. Just the CLI tool we use internally that I mentioned in the example :)

alienator88 avatar Dec 05 '22 22:12 alienator88

The point is to reuse UI code between a local desktop-Wails backend and a headless-remote-Wails backend(i.e. a go https server that uses the same Wails API to work with UI)? This way once the UI is done it remains to be same local and remote. Actually I think if Wails' API is compatible with json-rpc, e.g. UI <-- json-rpc --> Go-backend then the problem will be solved relatively easily, because json-rpc can work locally and over the internet.

laoshaw avatar Dec 05 '22 22:12 laoshaw

Did this finally work. I am looking to run a localhost myself. https://github.com/wailsapp/wails/issues/2189

ganeshkbhat avatar Dec 15 '22 07:12 ganeshkbhat

I wanted to bump this thread as I quite extensively worked on this topic in my own repository.

Basically I decoupled what is called "devserver" and "desktop" frontends in the master branch. In my reimplementation all communications including such edge cases like reload in dev mode are completely running though the messageDispatcher interface. One now can (theoretically) create a slice of multiple frontend interfaces in App.frontend that can practically run independently.

The implementation also minimizes code duplication as it uses a single code for server and/or desktop frontend and dev+hybrid combination mode are now simply a linear combination of the same basic server+desktop frontends.

Feel free to have a look m29h/feature/add_support_for_server_and_hybrid. I would be happy make a pull request if you consider my approach useful.

m29h avatar Feb 15 '23 00:02 m29h

Howdy! That is basically the approach I was taking but I haven't finished what I was doing. I'll check out your version. I bet it would be useful to the project. Obviously I haven't been very active here in a while although I still am interested in contributing more in the near future.

tmclane avatar Feb 15 '23 14:02 tmclane

@leaanthony Is there any benefit to attempting to get this finished up and brought in to v2? @m29h 's work looks good to me. I wanted to also rewrite the devserver itself since it seems a bit messy BUT it does function as it is.

tmclane avatar Feb 17 '23 20:02 tmclane

My only concern with a server build right now will be the inevitable requests for extending it with middleware and all the functionality people have when deploying server apps with a standard webserver. I'm very keen to get a server target, I just think we need to get a few people involved in that conversation and determine how best to do it. For instance, if we were able to generate an app as a Caddy plugin, then you'd get all the middleware and auth etc for free.

leaanthony avatar Feb 17 '23 20:02 leaanthony

I have no issue with using Caddy in the future.

I think the best suggestion for the moment is to use a reverse proxy that provides the authentication layer such that one wasn't need at the application level. This would allow this feature to be added with the caveat that there is ZERO authentication present at this time. Honestly who is going to using this on an untrusted network?

tmclane avatar Feb 17 '23 21:02 tmclane

I agree with @tmclane that a reverse proxy would suffice for all authentication needs. (if authentication would even needed for a particular app) Practically the benefit of such a wails "server" app lies in the rapid development possibilities due to the wails internal tooling for hot reload + automated bindings generation. Given that the multiple browser connections would all share the same App internal state, doing any sophisticated user management and authentications is probably not the primary use case.

However I see many uses for a remote browser accessible app on a local trusted network where all browser access instances share the same app state. This could for example be:

  • a local system app running on a 127.0.0.1 port for all users of the local machine. (persisting between logins)
  • some kind of home automation app running on a trusted network
  • Human-Machine-Interfaces, etc that benefit from the low level programming possibilities of the Go backend

The code draft I propose a week ago also would not introduce any significant amount of potentially "stale" code that is exclusively for the server use-case as it shares this server code with the current devserver. The idea is that it is more of a generalization of mechanisms that are already there today.

m29h avatar Feb 21 '23 00:02 m29h

I am going to look at a way to utilize caddy for this purpose such that it can be extended / configured using a Caddyfile.

tmclane avatar Feb 22 '23 17:02 tmclane

Let me know how I can help, if needed!

mholt avatar Feb 22 '23 18:02 mholt

Is there any progress in this PR? It could be really useful in one of our projects at VEGA. We are experiencing some issues when testing our wallet app, which we believe may be caused by desktop app being run in the same time we're performing tests in browser.

radoslaw-szpiech avatar Mar 15 '23 16:03 radoslaw-szpiech