mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-06 10:19:31 +08:00

* Add service registration method * Fix error handling and formatting in messageprocessor * Add configurable error handling * Improve error strings * Fix service shutdown on macOS * Add post shutdown hook * Better fatal errors * Add startup/shutdown sequence tests * Improve debug messages * Update JS runtime * Update docs * Update changelog * Fix log message in clipboard message processor Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Remove panic in RegisterService * Fix linux tests (hopefully) * Fix error formatting everywhere * Fix typo in windows webview * Tidy example mods * Set application name in tests * Fix ubuntu test workflow * Cleanup template test pipeline * Fix dev build detection on Go 1.24 * Update template go.mod/sum to Go 1.24 * Remove redundant caching in template tests * Final format string cleanup * Fix wails3 tool references * Fix legacy log calls * Remove formatJS and simplify format strings * Fix indirect import --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
105 lines
2.0 KiB
Go
105 lines
2.0 KiB
Go
package application
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"runtime/debug"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func getStackTrace(skipStart int, skipEnd int) string {
|
|
// Get all program counters first
|
|
pc := make([]uintptr, 32)
|
|
n := runtime.Callers(skipStart+1, pc)
|
|
if n == 0 {
|
|
return ""
|
|
}
|
|
|
|
pc = pc[:n]
|
|
frames := runtime.CallersFrames(pc)
|
|
|
|
// Collect all frames first
|
|
var allFrames []runtime.Frame
|
|
for {
|
|
frame, more := frames.Next()
|
|
allFrames = append(allFrames, frame)
|
|
if !more {
|
|
break
|
|
}
|
|
}
|
|
|
|
// Remove frames from the end
|
|
if len(allFrames) > skipEnd {
|
|
allFrames = allFrames[:len(allFrames)-skipEnd]
|
|
}
|
|
|
|
// Build the output string
|
|
var builder strings.Builder
|
|
for _, frame := range allFrames {
|
|
fmt.Fprintf(&builder, "%s\n\tat %s:%d\n",
|
|
frame.Function, frame.File, frame.Line)
|
|
}
|
|
return builder.String()
|
|
}
|
|
|
|
type handlePanicOptions struct {
|
|
skipEnd int
|
|
}
|
|
|
|
type PanicDetails struct {
|
|
StackTrace string
|
|
Error error
|
|
Time time.Time
|
|
FullStackTrace string
|
|
}
|
|
|
|
func newPanicDetails(err error, trace string) *PanicDetails {
|
|
return &PanicDetails{
|
|
Error: err,
|
|
Time: time.Now(),
|
|
StackTrace: trace,
|
|
FullStackTrace: string(debug.Stack()),
|
|
}
|
|
}
|
|
|
|
// handlePanic handles any panics
|
|
// Returns the error if there was one
|
|
func handlePanic(options ...handlePanicOptions) bool {
|
|
// Try to recover
|
|
e := recover()
|
|
if e == nil {
|
|
return false
|
|
}
|
|
|
|
// Get the error
|
|
err, ok := e.(error)
|
|
if !ok {
|
|
err = fmt.Errorf("%v", e)
|
|
}
|
|
|
|
// Get the stack trace
|
|
var stackTrace string
|
|
skipEnd := 0
|
|
if len(options) > 0 {
|
|
skipEnd = options[0].skipEnd
|
|
}
|
|
stackTrace = getStackTrace(3, skipEnd)
|
|
|
|
processPanic(newPanicDetails(err, stackTrace))
|
|
return false
|
|
}
|
|
|
|
func processPanic(panicDetails *PanicDetails) {
|
|
h := globalApplication.options.PanicHandler
|
|
if h != nil {
|
|
h(panicDetails)
|
|
return
|
|
}
|
|
defaultPanicHandler(panicDetails)
|
|
}
|
|
|
|
func defaultPanicHandler(panicDetails *PanicDetails) {
|
|
globalApplication.fatal("panic error: %w\n%s", panicDetails.Error, panicDetails.StackTrace)
|
|
}
|