-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Feature/add support for server and hybrid #1652
base: master
Are you sure you want to change the base?
Conversation
Deploying wails with Cloudflare Pages
|
45a00f3
to
2b558ad
Compare
2b558ad
to
f673d1a
Compare
@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 |
I'll look into that although it leads to a few questions.
|
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. |
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. |
You've described my use-case as well. I'll look into getting the |
Thank you for testing! I'll have an update soon hopefully time permitting. |
Travis, My main changes are enforcing the null frontend to call the 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. |
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 kee rebasing until we get it merged to main. |
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. |
b949618
to
d0a867b
Compare
@m29h Your commit has been included in this branch. |
d0a867b
to
bcc395b
Compare
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. |
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 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. |
It will be rebased and then updated to match the current state of the codebase. |
Actually I was redoing this work in a new way. This may be discarded.. |
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! |
I wasn't planning on adding authentication to the endpoint immediately. Sounds like that needs to be put on the roadmap as well. |
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 :) |
bcc395b
to
ea84b93
Compare
This probably isn't helpful as it could be incredibly niche, but just in case it spurs any ideas... I have recently implemented an HTTP server for my Wails app in such a way that its core application logic (the app bindings, basically -- the functions that can be called by the frontend) can be accessed these ways:
Basically, I still have an func (a *App) DoSomething(a string, b int) (Result, error) {
...
} then it can still be called by the JS frontend via Wails bindings like normal: import { DoSomething } from "../wailsjs/go/main/App.js";
const result = await DoSomething("foo", 3.14); Now, my app also has a a.server.mux = http.NewServeMux()
// SPA static file server
a.server.staticFiles = http.FileServer(http.FS(a.frontend))
a.server.mux.Handle("/", Endpoint{
Method: http.MethodGet,
Handler: a.server.serveFrontend,
})
// API endpoints
for command, endpoint := range a.commands {
a.server.mux.Handle("/api/"+command, endpoint)
} What is commands map[string]Endpoint The key of this map is the last component of the API URI, e.g. type Endpoint struct {
Method string
ContentType string
Payload any // example of the input
Handler http.Handler
Help string // help text for CLI
} For example: a.commands = map[string]Endpoint{
"do-something": {
Handler: a.server.handleDoSomething,
ContentType: "application/json",
Method: http.MethodPost,
Payload: MyStruct{},
Help: "Does something!",
},
... The func (e Endpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch e.ContentType {
case JSON:
payload := reflect.New(reflect.TypeOf(e.Payload)).Interface()
if r.ContentLength > 0 {
err := json.NewDecoder(r.Body).Decode(&payload)
// (handle err)
}
r = r.WithContext(context.WithValue(r.Context(), "payload", payload))
}
e.Handler(w, r)
} Then func (s *server) handleDoSomething(w http.ResponseWriter, r *http.Request) {
payload := r.Context().Value("payload").(*MyStruct)
result, err := s.app.DoSomething(payload.Foo, payload.Bar)
jsonResponse(w, result, err)
} (The With a little more code, this gives us a CLI for free now too, so I can do something like this:
This is possible because we know how to look up "do-something" in the map of commands, and with the My solution may be incredibly too niche, I realize. I just wanted to put it out here in case it inspires some ideas for the future. Pros to this approach:
Cons to this approach:
For me, the cons are pretty minor, and the benefits are big: I get 3 powerful ways to call my business logic, that all look and act the same, because under the hood they are the same. It's just a matter of linking the App function to an HTTP handler and a CLI. Feel free to ignore this though, I realize it might seem complicated 🙃 For context: I actually had to stop using Wails for my app because my UI has pretty intensive stuff going on that Webkit2GTK chokes on: canvas, webgl, lots of media, videos, etc -- Wails itself is great but webkit2gtk keeps crashing and having numerous other issues, video driver problems, etc. So anyway, that's my motivation for working on this independently; I don't strictly need a hybrid model per-se, but my solution is close to one. |
Bravo @mholt!
This is exactly what I'll be needing, and I'm sure a lot of people would find it handy too. Thanks a lot for sharing, which I'm fully confident that it'll work with Caddy in the future if we need it, :). |
ea84b93
to
658dbaf
Compare
Looks great, can't wait for this to be merged! |
658dbaf
to
ff3bcc6
Compare
Yes this will breat a great addition ! |
ff3bcc6
to
783957f
Compare
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
hi @leaanthony any eta on this? |
This isn't planned for inclusion at this time in v2. This is left in the repo so that industrious users can leverage it and expand on it but doesn't really have official support. That being said I can rebase it sometime and push it up again and then you could update your reference to use it. |
783957f
to
207b849
Compare
207b849
to
1a3657e
Compare
1a3657e
to
f4c9976
Compare
So, given this branch probably won't be merged to v2 anytime soon, and the fact that I kinda need this feature; How can i switch my current wails setup to this hybrid branch? should i just fork it? |
For v2, that's probably your best option at this point. |
Hit me up on the discord server for Wails. |
f4c9976
to
983332b
Compare
Quality Gate passedIssues Measures |
why this code not merged in v2.9 ? |
So, I first removed original wails CLI:
forked the branch and cloned the repo locally and first rebuilt the CLI:
Then, in the wails project in the
Then I tried to build a hybrid using but it returns the following error: • Generating bindings: ERROR
# github.com/wailsapp/wails/v2/internal/frontend/devserver
../../../../wails-custom/v2/internal/frontend/devserver/devserver.go:100:34: undefined: assetserver.NewDevAssetServer
exit status 1
ERROR
# github.com/wailsapp/wails/v2/internal/frontend/devserver
../../../../wails-custom/v2/internal/frontend/devserver/devserver.go:100:34: undefined: assetserver.NewDevAssetServer
exit status 1 Is there maybe some kind of #define/compiler option I forgot? |
null.Frontend does nothing and is merely needed to pass to the devserver so it has a frontend.Frontend to drive
- websocket client connection/disconnections - server endpoint
go.embed asset handling in production build call the OnStartup() callback when running the null frontend structure the app_hybrid_server.go to follow the structure and code of app_production.go
983332b
to
66f7239
Compare
This is a first pass implementation of a Wails target type of
server
andhybrid
.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
Hybrid
Default port is :
3112