mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-04 03:10:22 +08:00
Update docs + examples.
Serve runtime from assetserver if requested. Add gin guide, fix asset server merge, add gin example adding http.CloseNotifier and http.Flusher interface to assetserver.contentTypeSniffer, for Gin (and other framework) compatibility.
This commit is contained in:
parent
b72782c35d
commit
da99ea47b0
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Using Gin with Wails
|
||||
title: Using Gin for Routing
|
||||
description: A comprehensive guide to integrating Gin web framework with Wails v3 applications
|
||||
---
|
||||
|
||||
|
@ -1,19 +1,41 @@
|
||||
---
|
||||
title: Using Gin in Services
|
||||
title: Using Gin for Services
|
||||
description: A guide to integrating the Gin web framework with Wails v3 Services
|
||||
---
|
||||
|
||||
Wails v3 Services provide a powerful way to organize your application logic into reusable, modular components. By implementing the `http.Handler` interface in your services, you can mount them at specific routes in your application, allowing for a clean separation of concerns and more maintainable code.
|
||||
# Using Gin for Services
|
||||
|
||||
Integrating Gin with Wails Services enables you to create modular, mountable HTTP APIs using Gin's powerful routing and middleware capabilities. You can organize your application into domain-specific services, mount multiple Gin-based services at different routes, leverage Gin's extensive feature set while maintaining the benefits of Wails Services, and seamlessly integrate with the Wails event system for real-time communication.
|
||||
The Gin web framework is a popular choice for building HTTP services in Go. With Wails v3, you can easily integrate Gin-based services into your application, providing a powerful way to handle HTTP requests, implement RESTful APIs, and serve web content.
|
||||
|
||||
## Creating a Gin-based Service
|
||||
This guide will walk you through creating a Gin-based service that can be mounted at a specific route in your Wails application. We'll build a complete example that demonstrates how to:
|
||||
|
||||
To create a Wails Service that uses Gin for HTTP handling, you need to implement both the Wails Service interface and the `http.Handler` interface. This combination allows your service to be managed by the Wails application lifecycle and handle HTTP requests. Let's walk through each step of the process:
|
||||
1. Create a Gin-based service
|
||||
2. Implement the Wails Service interface
|
||||
3. Set up routes and middleware
|
||||
4. Integrate with the Wails event system
|
||||
5. Interact with the service from the frontend
|
||||
|
||||
### 1. Define Your Service Structure
|
||||
## Prerequisites
|
||||
|
||||
First, create a new service structure that will hold your Gin router and any state your service needs. This structure serves as the foundation of your service, encapsulating both the HTTP handling capabilities and any business logic or data your service requires. The use of a mutex ensures thread-safe access to shared resources, which is essential for concurrent request handling.
|
||||
Before you begin, make sure you have:
|
||||
|
||||
- Wails v3 installed
|
||||
- Basic knowledge of Go and the Gin framework
|
||||
- Familiarity with HTTP concepts and RESTful APIs
|
||||
|
||||
You'll need to add the Gin framework to your project:
|
||||
|
||||
```bash
|
||||
go get github.com/gin-gonic/gin
|
||||
```
|
||||
|
||||
## Creating a Gin-Based Service
|
||||
|
||||
Let's start by creating a Gin service that implements the Wails Service interface. Our service will manage a collection of users and provide API endpoints for retrieving and creating user records.
|
||||
|
||||
### 1. Define Your Data Models
|
||||
|
||||
First, define the data structures your service will work with:
|
||||
|
||||
```go
|
||||
package services
|
||||
@ -21,6 +43,7 @@ package services
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -36,6 +59,18 @@ type User struct {
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
// EventData represents data sent in events
|
||||
type EventData struct {
|
||||
Message string `json:"message"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Create Your Service Structure
|
||||
|
||||
Next, define the service structure that will hold your Gin router and any state your service needs to maintain:
|
||||
|
||||
```go
|
||||
// GinService implements a Wails service that uses Gin for HTTP handling
|
||||
type GinService struct {
|
||||
ginEngine *gin.Engine
|
||||
@ -71,9 +106,9 @@ func NewGinService() *GinService {
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Implement the Wails Service Interface
|
||||
### 3. Implement the Service Interface
|
||||
|
||||
Your service needs to implement the Wails Service interface with the required methods. The `ServiceName` method provides a human-readable identifier for your service. The `ServiceStartup` method is called when the service starts and gives you access to the Wails application instance, which you can use to register event handlers and access other Wails features. The `ServiceShutdown` method allows you to clean up resources when the service is shutting down.
|
||||
Implement the required methods for the Wails Service interface:
|
||||
|
||||
```go
|
||||
// ServiceName returns the name of the service
|
||||
@ -122,7 +157,7 @@ func (s *GinService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
### 4. Set Up Your Routes
|
||||
|
||||
Define your API routes in a separate method for better organization. This approach keeps your code clean and makes it easier to understand the structure of your API. The Gin router provides a fluent API for defining routes, including support for route groups, which help organize related endpoints.
|
||||
Define your API routes in a separate method for better organisation. This approach keeps your code clean and makes it easier to understand the structure of your API. The Gin router provides a fluent API for defining routes, including support for route groups, which help organise related endpoints.
|
||||
|
||||
```go
|
||||
// setupRoutes configures the API routes
|
||||
@ -191,6 +226,29 @@ func (s *GinService) setupRoutes() {
|
||||
// Emit an event to notify about the new user
|
||||
s.app.EmitEvent("user-created", newUser)
|
||||
})
|
||||
|
||||
// Delete a user
|
||||
users.DELETE("/:id", func(c *gin.Context) {
|
||||
id, err := strconv.Atoi(c.Param("id"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
for i, user := range s.users {
|
||||
if user.ID == id {
|
||||
// Remove the user from the slice
|
||||
s.users = append(s.users[:i], s.users[i+1:]...)
|
||||
c.JSON(http.StatusOK, gin.H{"message": "User deleted"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -241,7 +299,7 @@ app := application.New(application.Options{
|
||||
})
|
||||
```
|
||||
|
||||
In this example, the Gin service is mounted at the `/api` route. This means that if your Gin router has an endpoint defined as `/info`, it will be accessible at `/api/info` in your application. This approach allows you to organize your API endpoints logically and avoid conflicts with other parts of your application.
|
||||
In this example, the Gin service is mounted at the `/api` route. This means that if your Gin router has an endpoint defined as `/info`, it will be accessible at `/api/info` in your application. This approach allows you to organise your API endpoints logically and avoid conflicts with other parts of your application.
|
||||
|
||||
## Integrating with the Wails Event System
|
||||
|
||||
@ -285,7 +343,7 @@ Then use it in your code:
|
||||
import * as wails from '@wailsio/runtime';
|
||||
|
||||
// Event emission
|
||||
wails.Events.Emit({name: 'gin-api-event', data: eventData});
|
||||
wails.Events.Emit('gin-api-event', eventData);
|
||||
```
|
||||
|
||||
Here's an example of how to set up frontend integration:
|
||||
@ -310,7 +368,8 @@ Here's an example of how to set up frontend integration:
|
||||
<button id="getUsers">Get All Users</button>
|
||||
<button id="getUser">Get User by ID</button>
|
||||
<button id="createUser">Create User</button>
|
||||
|
||||
<button id="deleteUser">Delete User</button>
|
||||
|
||||
<div id="apiResult">
|
||||
<pre id="apiResponse">Results will appear here...</pre>
|
||||
</div>
|
||||
@ -327,8 +386,23 @@ Here's an example of how to set up frontend integration:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User creation form omitted for brevity -->
|
||||
|
||||
<div class="card" id="createUserForm" style="display: none; border: 2px solid #0078d7;">
|
||||
<h2>Create New User</h2>
|
||||
|
||||
<div>
|
||||
<label for="userName">Name:</label>
|
||||
<input type="text" id="userName" placeholder="Enter name">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="userEmail">Email:</label>
|
||||
<input type="email" id="userEmail" placeholder="Enter email">
|
||||
</div>
|
||||
|
||||
<button id="submitUser">Submit</button>
|
||||
<button id="cancelCreate">Cancel</button>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
// Import the Wails runtime
|
||||
// Note: In production, use '@wailsio/runtime' instead
|
||||
@ -353,8 +427,85 @@ Here's an example of how to set up frontend integration:
|
||||
fetchAPI('/info');
|
||||
});
|
||||
|
||||
// Other API button handlers omitted for brevity
|
||||
|
||||
document.getElementById('getUsers').addEventListener('click', () => {
|
||||
fetchAPI('/users');
|
||||
});
|
||||
|
||||
document.getElementById('getUser').addEventListener('click', async () => {
|
||||
const userId = prompt('Enter user ID:');
|
||||
if (userId) {
|
||||
await fetchAPI(`/users/${userId}`);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('createUser').addEventListener('click', () => {
|
||||
const form = document.getElementById('createUserForm');
|
||||
form.style.display = 'block';
|
||||
form.scrollIntoView({ behavior: 'smooth' });
|
||||
});
|
||||
|
||||
document.getElementById('cancelCreate').addEventListener('click', () => {
|
||||
document.getElementById('createUserForm').style.display = 'none';
|
||||
});
|
||||
|
||||
document.getElementById('submitUser').addEventListener('click', async () => {
|
||||
const name = document.getElementById('userName').value;
|
||||
const email = document.getElementById('userEmail').value;
|
||||
|
||||
if (!name || !email) {
|
||||
alert('Please enter both name and email');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await fetchAPI('/users', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ name, email })
|
||||
});
|
||||
|
||||
document.getElementById('createUserForm').style.display = 'none';
|
||||
document.getElementById('userName').value = '';
|
||||
document.getElementById('userEmail').value = '';
|
||||
|
||||
// Automatically fetch the updated user list
|
||||
await fetchAPI('/users');
|
||||
|
||||
// Show a success message
|
||||
const apiResponse = document.getElementById('apiResponse');
|
||||
const currentData = JSON.parse(apiResponse.textContent);
|
||||
apiResponse.textContent = JSON.stringify({
|
||||
message: "User created successfully!",
|
||||
users: currentData
|
||||
}, null, 2);
|
||||
} catch (error) {
|
||||
console.error('Error creating user:', error);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('deleteUser').addEventListener('click', async () => {
|
||||
const userId = prompt('Enter user ID to delete:');
|
||||
if (userId) {
|
||||
try {
|
||||
await fetchAPI(`/users/${userId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
// Show success message
|
||||
document.getElementById('apiResponse').textContent = JSON.stringify({
|
||||
message: `User with ID ${userId} deleted successfully`
|
||||
}, null, 2);
|
||||
|
||||
// Refresh the user list
|
||||
setTimeout(() => fetchAPI('/users'), 1000);
|
||||
} catch (error) {
|
||||
console.error('Error deleting user:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Using Wails Events API for event communication
|
||||
document.getElementById('triggerEvent').addEventListener('click', async () => {
|
||||
// Display the event being sent
|
||||
@ -378,6 +529,14 @@ Here's an example of how to set up frontend integration:
|
||||
document.getElementById('eventResponse').textContent = JSON.stringify(data, null, 2);
|
||||
});
|
||||
|
||||
// Also listen for user-created events
|
||||
wails.Events.On("user-created", (data) => {
|
||||
document.getElementById('eventResponse').textContent = JSON.stringify({
|
||||
event: "user-created",
|
||||
user: data
|
||||
}, null, 2);
|
||||
});
|
||||
|
||||
// Initial API call to get service info
|
||||
fetchAPI('/info');
|
||||
});
|
||||
@ -386,22 +545,6 @@ Here's an example of how to set up frontend integration:
|
||||
</html>
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
When using Gin with Wails Services, consider these best practices for creating maintainable and efficient applications:
|
||||
|
||||
- Modular Design: Organize your API endpoints into logical groups using Gin's router groups. This makes your code more readable and easier to maintain.
|
||||
|
||||
- Concurrency Safety: Use mutexes or other synchronization primitives when accessing shared state. This prevents race conditions and ensures data integrity.
|
||||
|
||||
- Error Handling: Implement consistent error handling across your API endpoints. This provides a better user experience and makes debugging easier.
|
||||
|
||||
- Logging: Use the Wails logger for consistent logging throughout your application. This helps with debugging and monitoring.
|
||||
|
||||
- Event-Driven Communication: Use the Wails event system for real-time updates and notifications. This creates a more responsive and interactive user experience.
|
||||
|
||||
- Security: Implement proper authentication and authorization for your API endpoints. This protects your application and user data.
|
||||
|
||||
## Closing Thoughts
|
||||
|
||||
Integrating the Gin web framework with Wails v3 Services provides a powerful and flexible approach to building modular, maintainable web applications. By leveraging Gin's routing and middleware capabilities alongside the Wails event system, you can create rich, interactive applications with clean separation of concerns.
|
||||
|
@ -9,7 +9,7 @@
|
||||
<h1>Events Demo</h1>
|
||||
<br/>
|
||||
The main program emits an event every 10s which will be displayed in the section below.
|
||||
To send an event from this window, click here: <button onclick="wails.Events.Emit({name:'myevent', data:'hello!'})">Send Event</button>
|
||||
To send an event from this window, click here: <button onclick="wails.Events.Emit('myevent', 'hello!')">Send Event</button>
|
||||
<div id="results"></div>
|
||||
</body>
|
||||
|
||||
|
26
v3/examples/gin-routing/README.md
Normal file
26
v3/examples/gin-routing/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
# Gin Routing Example
|
||||
|
||||
This example demonstrates how to use the [Gin web framework](https://github.com/gin-gonic/gin) as a router with Wails.
|
||||
|
||||
## Overview
|
||||
|
||||
This example shows how to:
|
||||
|
||||
- Set up Gin as the asset handler for a Wails application
|
||||
- Create a middleware that routes requests between Wails and Gin
|
||||
- Define API endpoints with Gin
|
||||
- Communicate between the Gin-served frontend and Wails backend
|
||||
- Implement custom Gin middleware
|
||||
|
||||
## Running the Example
|
||||
|
||||
```bash
|
||||
cd v3/examples/gin-routing
|
||||
go mod tidy
|
||||
go run .
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Please consult the [Using Gin for Routing](https://v3.wails.io/guides/gin-routing/) guide for a detailed explanation of the example.
|
||||
|
72
v3/examples/gin-routing/go.mod
Normal file
72
v3/examples/gin-routing/go.mod
Normal file
@ -0,0 +1,72 @@
|
||||
module gin-example
|
||||
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/wailsapp/wails/v3 v3.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.5 // indirect
|
||||
github.com/adrg/xdg v0.5.3 // indirect
|
||||
github.com/bep/debounce v1.2.1 // indirect
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/cloudflare/circl v1.6.0 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.2 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.13.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1 // indirect
|
||||
github.com/leaanthony/u v1.1.1 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/lmittmann/tint v1.0.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/samber/lo v1.49.1 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/wailsapp/go-webview2 v1.0.19 // indirect
|
||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.33.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/wailsapp/wails/v3 => ../../
|
203
v3/examples/gin-routing/go.sum
Normal file
203
v3/examples/gin-routing/go.sum
Normal file
@ -0,0 +1,203 @@
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
|
||||
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
|
||||
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
|
||||
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
|
||||
github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
|
||||
github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
|
||||
github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
|
||||
github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
|
||||
github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/lmittmann/tint v1.0.7 h1:D/0OqWZ0YOGZ6AyC+5Y2kD8PBEzBk6rFHVSfOqCkF9Y=
|
||||
github.com/lmittmann/tint v1.0.7/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
|
||||
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
|
||||
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/wailsapp/go-webview2 v1.0.19 h1:7U3QcDj1PrBPaxJNCui2k1SkWml+Q5kvFUFyTImA6NU=
|
||||
github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20220715151400-c0bba94af5f8/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.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.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.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
114
v3/examples/gin-routing/main.go
Normal file
114
v3/examples/gin-routing/main.go
Normal file
@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
//go:embed static
|
||||
var staticFiles embed.FS
|
||||
|
||||
// GinMiddleware creates a middleware that passes requests to Gin if they're not handled by Wails
|
||||
func GinMiddleware(ginEngine *gin.Engine) application.Middleware {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Let Wails handle the `/wails` route
|
||||
if strings.HasPrefix(r.URL.Path, "/wails") {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
// Let Gin handle everything else
|
||||
ginEngine.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// LoggingMiddleware is a Gin middleware that logs request details
|
||||
func LoggingMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// Start timer
|
||||
startTime := time.Now()
|
||||
|
||||
// Process request
|
||||
c.Next()
|
||||
|
||||
// Calculate latency
|
||||
latency := time.Since(startTime)
|
||||
|
||||
// Log request details
|
||||
log.Printf("[GIN] %s | %s | %s | %d | %s",
|
||||
c.Request.Method,
|
||||
c.Request.URL.Path,
|
||||
c.ClientIP(),
|
||||
c.Writer.Status(),
|
||||
latency,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Create a new Gin router
|
||||
ginEngine := gin.New() // Using New() instead of Default() to add our own middleware
|
||||
|
||||
// Add middlewares
|
||||
ginEngine.Use(gin.Recovery())
|
||||
ginEngine.Use(LoggingMiddleware())
|
||||
|
||||
// Serve embedded static files
|
||||
ginEngine.StaticFS("/static", http.FS(staticFiles))
|
||||
|
||||
// Define routes
|
||||
ginEngine.GET("/", func(c *gin.Context) {
|
||||
file, err := staticFiles.ReadFile("static/index.html")
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Error reading index.html")
|
||||
return
|
||||
}
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", file)
|
||||
})
|
||||
|
||||
ginEngine.GET("/api/hello", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "Hello from Gin API!",
|
||||
"time": time.Now().Format(time.RFC3339),
|
||||
})
|
||||
})
|
||||
|
||||
// Create a new Wails application
|
||||
app := application.New(application.Options{
|
||||
Name: "Gin Example",
|
||||
Description: "A demo of using Gin with Wails",
|
||||
Mac: application.MacOptions{
|
||||
ApplicationShouldTerminateAfterLastWindowClosed: true,
|
||||
},
|
||||
Assets: application.AssetOptions{
|
||||
Handler: ginEngine,
|
||||
Middleware: GinMiddleware(ginEngine),
|
||||
},
|
||||
})
|
||||
|
||||
// Register event handler
|
||||
app.OnEvent("gin-button-clicked", func(event *application.CustomEvent) {
|
||||
log.Printf("Received event from frontend: %v", event.Data)
|
||||
})
|
||||
|
||||
// Create window
|
||||
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
|
||||
Title: "Wails + Gin Example",
|
||||
Width: 900,
|
||||
Height: 700,
|
||||
URL: "/",
|
||||
})
|
||||
|
||||
// Run the app
|
||||
err := app.Run()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
94
v3/examples/gin-routing/static/index.html
Normal file
94
v3/examples/gin-routing/static/index.html
Normal file
@ -0,0 +1,94 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Wails + Gin Example</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f5f5f5;
|
||||
color: #333;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
h1 {
|
||||
color: #0078d7;
|
||||
}
|
||||
.card {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
button {
|
||||
background-color: #0078d7;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0063b1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Wails + Gin Integration</h1>
|
||||
<div class="card">
|
||||
<h2>Hello World!</h2>
|
||||
<p>This page is being served by Gin.</p>
|
||||
<p>Click the button below to trigger a Wails event:</p>
|
||||
<button id="triggerEvent">Trigger Event</button>
|
||||
<div id="eventResult" style="margin-top: 1rem; padding: 1rem; background-color: #f0f0f0; border-radius: 4px; display: none;"></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>API Example</h2>
|
||||
<p>Try the Gin API endpoint:</p>
|
||||
<button id="callApi">Call API</button>
|
||||
<div id="apiResult" style="margin-top: 1rem; padding: 1rem; background-color: #f0f0f0; border-radius: 4px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module">
|
||||
import * as wails from '/wails/runtime.js';
|
||||
|
||||
// Wait for the Wails runtime to be ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
setupEventListeners();
|
||||
});
|
||||
|
||||
function setupEventListeners() {
|
||||
document.getElementById('triggerEvent').addEventListener('click', async () => {
|
||||
try {
|
||||
console.log('Attempting to emit event...');
|
||||
await wails.Events.Emit('gin-button-clicked', 'Hello from Gin!');
|
||||
console.log('Event emitted successfully');
|
||||
document.getElementById('eventResult').textContent = 'Event emitted successfully!';
|
||||
document.getElementById('eventResult').style.display = 'block';
|
||||
} catch (error) {
|
||||
console.error('Error emitting event:', error);
|
||||
document.getElementById('eventResult').textContent = 'Error: ' + error.message;
|
||||
document.getElementById('eventResult').style.display = 'block';
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('callApi').addEventListener('click', async () => {
|
||||
try {
|
||||
const response = await fetch('/api/hello');
|
||||
const data = await response.json();
|
||||
document.getElementById('apiResult').textContent = JSON.stringify(data, null, 2);
|
||||
} catch (error) {
|
||||
console.error('Error calling API:', error);
|
||||
document.getElementById('apiResult').textContent = 'Error: ' + error.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
26
v3/examples/gin-service/README.md
Normal file
26
v3/examples/gin-service/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
# Gin Service Example
|
||||
|
||||
This example demonstrates how to use the [Gin web framework](https://github.com/gin-gonic/gin) in a Wails Service.
|
||||
|
||||
## Overview
|
||||
|
||||
This example shows how to:
|
||||
|
||||
- Set up Gin as the asset handler for a Wails application
|
||||
- Create a middleware that routes requests between Wails and Gin
|
||||
- Define API endpoints with Gin
|
||||
- Communicate between the Gin-served frontend and Wails backend
|
||||
- Implement custom Gin middleware
|
||||
|
||||
## Running the Example
|
||||
|
||||
```bash
|
||||
cd v3/examples/gin-routing
|
||||
go mod tidy
|
||||
go run .
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Please consult the [Using Gin for Routing](https://v3.wails.io/guides/gin-routing/) guide for a detailed explanation of the example.
|
||||
|
@ -73,6 +73,7 @@
|
||||
<button id="getUsers">Get All Users</button>
|
||||
<button id="getUser">Get User by ID</button>
|
||||
<button id="createUser">Create User</button>
|
||||
<button id="deleteUser">Delete User</button>
|
||||
|
||||
<div id="apiResult" style="margin-top: 1rem;">
|
||||
<pre id="apiResponse">Results will appear here...</pre>
|
||||
@ -188,6 +189,27 @@
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('deleteUser').addEventListener('click', async () => {
|
||||
const userId = prompt('Enter user ID to delete:');
|
||||
if (userId) {
|
||||
try {
|
||||
await fetchAPI(`/users/${userId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
// Show success message
|
||||
document.getElementById('apiResponse').textContent = JSON.stringify({
|
||||
message: `User with ID ${userId} deleted successfully`
|
||||
}, null, 2);
|
||||
|
||||
// Refresh the user list
|
||||
setTimeout(() => fetchAPI('/users'), 1000);
|
||||
} catch (error) {
|
||||
console.error('Error deleting user:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Using Wails Events API for event communication
|
||||
document.getElementById('triggerEvent').addEventListener('click', async () => {
|
||||
// Display the event being sent
|
||||
@ -211,6 +233,14 @@
|
||||
document.getElementById('eventResponse').textContent = JSON.stringify(data, null, 2);
|
||||
});
|
||||
|
||||
// Also listen for user-created events
|
||||
wails.Events.On("user-created", (data) => {
|
||||
document.getElementById('eventResponse').textContent = JSON.stringify({
|
||||
event: "user-created",
|
||||
user: data
|
||||
}, null, 2);
|
||||
});
|
||||
|
||||
// Initial API call to get service info
|
||||
fetchAPI('/info');
|
||||
});
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -125,11 +125,23 @@ export function OffAll(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the given event.
|
||||
* Emits an event using the name and data.
|
||||
*
|
||||
* @param event - The name of the event to emit.
|
||||
* @returns A promise that will be fulfilled once the event has been emitted.
|
||||
* @param name - the name of the event to emit.
|
||||
* @param data - the data to be sent with the event.
|
||||
*/
|
||||
export function Emit(event: WailsEvent): Promise<void> {
|
||||
export function Emit(name: string, data?: any): Promise<void> {
|
||||
let event: WailsEvent;
|
||||
|
||||
if (typeof name === 'object' && name !== null && 'name' in name && 'data' in name) {
|
||||
// If name is an object with a name property, use it directly
|
||||
event = new WailsEvent(name['name'], name['data']);
|
||||
} else {
|
||||
// Otherwise use the standard parameters
|
||||
event = new WailsEvent(name as string, data);
|
||||
}
|
||||
|
||||
return call(EmitMethod, event);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user