-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdeeplink_windows.go
150 lines (120 loc) · 3.37 KB
/
deeplink_windows.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package deeplink
import (
"fmt"
"golang.org/x/sys/windows/registry"
"log"
"net"
"os"
"path/filepath"
"strings"
)
type DeepLink struct {
// Scheme is the name of the scheme to register, for example "myapp" will be accessible via "myapp://"
Scheme string
// Host is the host to listen on, used for checking is the app is already running
Port uint
// OnMessage is called when a message is received, the message is passed as a string
OnMessage func(string)
}
// NewDeeplink creates a new DeepLink instance
// scheme is the name of the scheme to register, for example "myapp" will be accessible via "myapp://"
func NewDeeplink(scheme string, port uint) *DeepLink {
return &DeepLink{
Scheme: scheme,
Port: port,
}
}
// Register registers the scheme in the registry, this is required for the scheme to work
func (dl *DeepLink) Register(callback func(string)) (bool, error) {
exe, _ := os.Executable()
exePath := filepath.ToSlash(exe)
// reformat exePath to windows format
exePath = strings.Replace(exePath, "/", "\\", -1)
k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Classes\`+dl.Scheme, registry.ALL_ACCESS)
if err != nil {
k, _, err = registry.CreateKey(registry.CURRENT_USER, `Software\Classes\`+dl.Scheme, registry.ALL_ACCESS)
if err != nil {
log.Fatal("registry.CreateKey", err)
}
}
defer k.Close()
err = k.SetStringValue("", "URL:"+dl.Scheme)
if err != nil {
log.Fatal("k.SetStringValue", err)
}
err = k.SetStringValue("URL Protocol", "")
if err != nil {
log.Fatal("k.SetStringValue URL Protocol", err)
}
k2, _, err := registry.CreateKey(k, `DefaultIcon`, registry.ALL_ACCESS)
if err != nil {
log.Fatal("registry.CreateKey DefaultIcon", err)
}
err = k2.SetStringValue("", fmt.Sprintf("%s,0", exePath))
if err != nil {
log.Fatal("k2.SetStringValue", err)
}
k2.Close()
k3, _, err := registry.CreateKey(k, `shell\open\command`, registry.ALL_ACCESS)
if err != nil {
log.Fatal("registry.CreateKey shell\\open\\command", err)
}
err = k3.SetStringValue("", fmt.Sprintf("%s \"%%1\"", exePath))
if err != nil {
log.Fatal("k3.SetStringValue", err)
}
k3.Close()
dl.OnMessage = callback
return true, nil
}
// Unregister unregisters the scheme from the registry
func (dl *DeepLink) Unregister() (bool, error) {
err := registry.DeleteKey(registry.CURRENT_USER, `Software\Classes\`+dl.Scheme)
if err != nil {
log.Fatal("registry.DeleteKey", err)
}
return true, nil
}
func isAnotherProcessExists(port uint) bool {
conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil {
return false
}
conn.Close()
return true
}
func (dl *DeepLink) listen(port uint) {
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil {
log.Fatal(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
go func() {
buf := make([]byte, 1024)
n, _ := conn.Read(buf)
if n > 0 {
dl.OnMessage(string(buf[:n]))
}
}()
}
}
// Prepare prepares the DeepLink instance for receiving messages, this is required to redirect message to already running app
func (dl *DeepLink) Prepare() {
go func() {
if isAnotherProcessExists(dl.Port) {
conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", dl.Port))
if err != nil {
log.Fatal(err)
}
conn.Write([]byte(os.Args[len(os.Args)-1]))
conn.Close()
os.Exit(0)
} else {
dl.listen(dl.Port)
}
}()
}