@@ -38,37 +38,45 @@ func New() *Singcast {
3838 return & Singcast {svc : core .NewService ()}
3939}
4040
41+ // service returns the core.Service, initializing lazily for gomobile zero-value compatibility.
42+ func (s * Singcast ) service () * core.Service {
43+ if s .svc == nil {
44+ s .svc = core .NewService ()
45+ }
46+ return s .svc
47+ }
48+
4149// Init initializes the core runtime.
4250// optionsJSON: {"home_dir":"/path","log_max_lines":500,"debug":false,"fix_android_stack":false}
4351func (s * Singcast ) Init (optionsJSON string ) error {
44- return s .svc .Init (optionsJSON )
52+ return s .service () .Init (optionsJSON )
4553}
4654
4755// StartWithContent starts or restarts the service with raw YAML or JSON config.
4856func (s * Singcast ) StartWithContent (content , ruleSetProxy string ) error {
49- return s .svc .StartWithContent (content , ruleSetProxy )
57+ return s .service () .StartWithContent (content , ruleSetProxy )
5058}
5159
5260// Stop stops the running service. Safe to call multiple times.
5361func (s * Singcast ) Stop () error {
54- return s .svc .Stop ()
62+ return s .service () .Stop ()
5563}
5664
5765// Destroy releases all resources. The instance cannot be reused.
5866func (s * Singcast ) Destroy () {
59- s .svc .Destroy ()
67+ s .service () .Destroy ()
6068}
6169
6270// --- Platform IO ---
6371
6472// SetTunFd stores a TUN file descriptor for mobile platforms.
6573func (s * Singcast ) SetTunFd (fd int32 ) {
66- s .svc .PlatformIO ().SetTunFd (fd )
74+ s .service () .PlatformIO ().SetTunFd (fd )
6775}
6876
6977// SetSocketProtector registers a socket protector for VPN bypass.
7078func (s * Singcast ) SetSocketProtector (p SocketProtector ) {
71- s .svc .PlatformIO ().SetSocketProtector (func (fd int32 ) bool {
79+ s .service () .PlatformIO ().SetSocketProtector (func (fd int32 ) bool {
7280 if p != nil {
7381 return p .Protect (fd )
7482 }
@@ -78,64 +86,64 @@ func (s *Singcast) SetSocketProtector(p SocketProtector) {
7886
7987// SetInterfacesJSON provides network interface data from the mobile platform.
8088func (s * Singcast ) SetInterfacesJSON (json string ) {
81- s .svc .PlatformIO ().SetInterfacesJSON (json )
89+ s .service () .PlatformIO ().SetInterfacesJSON (json )
8290}
8391
8492// UpdateDefaultInterface reports the current default network interface.
8593func (s * Singcast ) UpdateDefaultInterface (name string , index int64 , expensive bool ) {
86- s .svc .PlatformIO ().UpdateDefaultInterface (name , index , expensive )
94+ s .service () .PlatformIO ().UpdateDefaultInterface (name , index , expensive )
8795}
8896
8997// SetIncludeAllNetworks sets whether the VPN configuration uses includeAllNetworks (iOS).
9098func (s * Singcast ) SetIncludeAllNetworks (v bool ) {
91- s .svc .PlatformIO ().SetIncludeAllNetworks (v )
99+ s .service () .PlatformIO ().SetIncludeAllNetworks (v )
92100}
93101
94102// SetWIFIState reports the current WiFi SSID and BSSID from the mobile platform.
95103func (s * Singcast ) SetWIFIState (ssid , bssid string ) {
96- s .svc .PlatformIO ().SetWIFIState (ssid , bssid )
104+ s .service () .PlatformIO ().SetWIFIState (ssid , bssid )
97105}
98106
99107// QueryTunOptions returns TUN configuration as JSON for mobile consumers.
100108// Call after the service has started (OpenTun has been invoked by sing-box).
101109func (s * Singcast ) QueryTunOptions () string {
102- return s .svc .PlatformIO ().QueryTunOptions ()
110+ return s .service () .PlatformIO ().QueryTunOptions ()
103111}
104112
105113// --- Logging ---
106114
107115// SetLogLevel sets the minimum log level (2=Error, 3=Warn, 4=Info, 5=Debug, 6=Trace).
108- func (s * Singcast ) SetLogLevel (level int32 ) { s .svc .SetLogLevel (level ) }
116+ func (s * Singcast ) SetLogLevel (level int32 ) { s .service () .SetLogLevel (level ) }
109117
110118// SetError pushes an error message to connected clients.
111- func (s * Singcast ) SetError (message string ) { s .svc .SetError (message ) }
119+ func (s * Singcast ) SetError (message string ) { s .service () .SetError (message ) }
112120
113121// --- Pause / Wake / Network ---
114122
115123// Pause suspends network activity. On iOS, auto-wakes after 1 minute.
116- func (s * Singcast ) Pause () { s .svc .Pause () }
124+ func (s * Singcast ) Pause () { s .service () .Pause () }
117125
118126// Wake resumes network activity after Pause.
119- func (s * Singcast ) Wake () { s .svc .Wake () }
127+ func (s * Singcast ) Wake () { s .service () .Wake () }
120128
121129// ResetNetwork resets all connections, DNS cache, and forces outbounds to reconnect.
122- func (s * Singcast ) ResetNetwork () { s .svc .ResetNetwork () }
130+ func (s * Singcast ) ResetNetwork () { s .service () .ResetNetwork () }
123131
124132// --- Config ---
125133
126134// ReloadConfig reloads the service with new configuration.
127135func (s * Singcast ) ReloadConfig (content , ruleSetProxy string ) error {
128- return s .svc .ReloadConfig (content , ruleSetProxy )
136+ return s .service () .ReloadConfig (content , ruleSetProxy )
129137}
130138
131139// ReloadTUN restarts the TUN interface without changing configuration.
132- func (s * Singcast ) ReloadTUN () error { return s .svc .ReloadTUN () }
140+ func (s * Singcast ) ReloadTUN () error { return s .service () .ReloadTUN () }
133141
134142// SetOverridePackages updates the include/exclude package lists for VPN split tunneling.
135143// The service restarts with the current config and new package overrides.
136144// Pass empty string to clear all overrides.
137145func (s * Singcast ) SetOverridePackages (overrideJSON string ) error {
138- return s .svc .SetOverridePackages (overrideJSON )
146+ return s .service () .SetOverridePackages (overrideJSON )
139147}
140148
141149// CheckConfig validates a config string (Clash YAML or sing-box JSON).
@@ -145,25 +153,25 @@ func (s *Singcast) CheckConfig(content string) error { return core.CheckConfig(c
145153
146154// SelectProxy selects a proxy in the given group.
147155func (s * Singcast ) SelectProxy (group , tag string ) error {
148- return s .svc .SelectOutbound (group , tag )
156+ return s .service () .SelectOutbound (group , tag )
149157}
150158
151159// TestDelay runs a URL test for the given outbound tag.
152- func (s * Singcast ) TestDelay (name string ) error { return s .svc .URLTest (name ) }
160+ func (s * Singcast ) TestDelay (name string ) error { return s .service () .URLTest (name ) }
153161
154162// SetMode sets the clash routing mode (rule, global, or direct).
155- func (s * Singcast ) SetMode (mode string ) error { return s .svc .SetClashMode (mode ) }
163+ func (s * Singcast ) SetMode (mode string ) error { return s .service () .SetClashMode (mode ) }
156164
157165// SetGroupExpand sets the UI expand state for a proxy group.
158166func (s * Singcast ) SetGroupExpand (group string , expand bool ) error {
159- return s .svc .SetGroupExpand (group , expand )
167+ return s .service () .SetGroupExpand (group , expand )
160168}
161169
162170// --- Queries ---
163171
164172// QueryProxies returns cached proxy groups as JSON.
165173func (s * Singcast ) QueryProxies () string {
166- h := s .svc .Handler ()
174+ h := s .service () .Handler ()
167175 if h == nil {
168176 return "[]"
169177 }
@@ -172,7 +180,7 @@ func (s *Singcast) QueryProxies() string {
172180
173181// QueryTraffic returns cached traffic stats as JSON.
174182func (s * Singcast ) QueryTraffic () string {
175- h := s .svc .Handler ()
183+ h := s .service () .Handler ()
176184 if h == nil {
177185 return "{}"
178186 }
@@ -182,49 +190,49 @@ func (s *Singcast) QueryTraffic() string {
182190// QueryLogs returns combined sing-box and core internal logs as JSON.
183191// If clear is true, the log buffer is cleared after querying.
184192func (s * Singcast ) QueryLogs (clear bool ) string {
185- result := s .svc .QueryLogs ()
193+ result := s .service () .QueryLogs ()
186194 if clear {
187- _ = s .svc .ClearLogs ()
195+ _ = s .service () .ClearLogs ()
188196 }
189197 return result
190198}
191199
192200// QueryConnections returns cached connections as JSON.
193201func (s * Singcast ) QueryConnections () string {
194- h := s .svc .Handler ()
202+ h := s .service () .Handler ()
195203 if h == nil {
196204 return "[]"
197205 }
198206 return h .GetCachedConnectionsJSON ()
199207}
200208
201209// CloseConnection closes a connection by ID.
202- func (s * Singcast ) CloseConnection (id string ) error { return s .svc .CloseConnection (id ) }
210+ func (s * Singcast ) CloseConnection (id string ) error { return s .service () .CloseConnection (id ) }
203211
204212// CloseAllConnections closes all active connections.
205- func (s * Singcast ) CloseAllConnections () error { return s .svc .CloseConnections () }
213+ func (s * Singcast ) CloseAllConnections () error { return s .service () .CloseConnections () }
206214
207215// --- Platform Queries ---
208216
209217// NeedWIFIState reports whether the current config requires WIFI state monitoring.
210- func (s * Singcast ) NeedWIFIState () bool { return s .svc .NeedWIFIState () }
218+ func (s * Singcast ) NeedWIFIState () bool { return s .service () .NeedWIFIState () }
211219
212220// NeedFindProcess reports whether the current config requires process finding.
213- func (s * Singcast ) NeedFindProcess () bool { return s .svc .NeedFindProcess () }
221+ func (s * Singcast ) NeedFindProcess () bool { return s .service () .NeedFindProcess () }
214222
215223// UpdateWIFIState triggers the platform to report current WIFI state.
216- func (s * Singcast ) UpdateWIFIState () { s .svc .UpdateWIFIState () }
224+ func (s * Singcast ) UpdateWIFIState () { s .service () .UpdateWIFIState () }
217225
218226// WriteMessage writes a log message to the core at the given level.
219227func (s * Singcast ) WriteMessage (level int32 , message string ) {
220- s .svc .WriteMessage (level , message )
228+ s .service () .WriteMessage (level , message )
221229}
222230
223231// FlushSystemDNS attempts to flush the system DNS cache.
224- func (s * Singcast ) FlushSystemDNS () { s .svc .FlushSystemDNS () }
232+ func (s * Singcast ) FlushSystemDNS () { s .service () .FlushSystemDNS () }
225233
226234// QueryMemoryStats returns current Go runtime memory statistics as JSON.
227- func (s * Singcast ) QueryMemoryStats () string { return s .svc .QueryMemoryStats () }
235+ func (s * Singcast ) QueryMemoryStats () string { return s .service () .QueryMemoryStats () }
228236
229237// --- Memory ---
230238
@@ -241,7 +249,7 @@ func (s *Singcast) Version() string { return core.VersionJSON() }
241249
242250// SetOnEvent registers an event handler. Call after Init.
243251func (s * Singcast ) SetOnEvent (handler EventHandler ) {
244- s .svc .SetOnEvent (func (eventType int32 , jsonPayload string ) {
252+ s .service () .SetOnEvent (func (eventType int32 , jsonPayload string ) {
245253 if handler != nil {
246254 handler .OnEvent (eventType , jsonPayload )
247255 }
0 commit comments