Skip to content
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

add a new SwiftUI client (build by SwiftUI) for macOS #3

Merged
merged 7 commits into from
May 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions client-ui/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fyne.io/fyne/dialog"
"fyne.io/fyne/theme"
"fyne.io/fyne/widget"
"github.com/genshen/wssocks-plugin-ustb/extra"
"github.com/genshen/wssocks-plugin-ustb/plugins/vpn"
"github.com/genshen/wssocks/version"
"net/url"
Expand Down Expand Up @@ -90,7 +91,7 @@ func main() {

btnStart := widget.NewButton("Start", nil)
btnStatus := btnStopped
var handles Handles
var handles extra.Handles
btnStart.OnTapped = func() {
if btnStatus == btnRunning { // running can stop
btnStatus = btnStopping
Expand All @@ -99,11 +100,11 @@ func main() {
btnStart.SetText("Start")
btnStatus = btnStopped
} else if btnStatus == btnStopped { // stopped can run
options := Options{
localSocks5Addr: uiLocalAddr.Text,
remoteAddr: uiRemoteAddr.Text,
httpEnable: uiHttpEnable.Checked,
localHttpAddr: uiHttpLocalAddr.Text,
options := extra.Options{
LocalSocks5Addr: uiLocalAddr.Text,
RemoteAddr: uiRemoteAddr.Text,
HttpEnable: uiHttpEnable.Checked,
LocalHttpAddr: uiHttpLocalAddr.Text,
UstbVpn: vpn.UstbVpn{
Enable: uiVpnEnable.Checked,
ForceLogout: uiVpnForceLogout.Checked,
Expand All @@ -115,7 +116,7 @@ func main() {
}
btnStatus = btnStarting
btnStart.SetText("Loading")
if err := handles.startWssocks(options); err != nil {
if err := handles.StartWssocks(options); err != nil {
// log error
dialog.ShowError(err, w)
btnStart.SetText("Start")
Expand Down
24 changes: 13 additions & 11 deletions client-ui/background.go → extra/background.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package main
// this file provide api for launching and stopping client

package extra

import (
"context"
Expand All @@ -16,10 +18,10 @@ import (
type Options struct {
vpn.UstbVpn
remoteUrl *url.URL
localSocks5Addr string
remoteAddr string
httpEnable bool
localHttpAddr string
LocalSocks5Addr string
RemoteAddr string
HttpEnable bool
LocalHttpAddr string
}

type Handles struct {
Expand Down Expand Up @@ -49,12 +51,12 @@ func (h *Handles) Close() {
h.wg.Wait() // wait tasks finishing
}

func (h *Handles) startWssocks(o Options) error {
func (h *Handles) StartWssocks(o Options) error {
// check remote url
if o.remoteAddr == "" {
if o.RemoteAddr == "" {
return errors.New("empty remote address")
}
if u, err := url.Parse(o.remoteAddr); err != nil {
if u, err := url.Parse(o.RemoteAddr); err != nil {
return err
} else {
o.remoteUrl = u
Expand Down Expand Up @@ -99,12 +101,12 @@ func (h *Handles) startWssocks(o Options) error {
}()

record := wss.NewConnRecord() // connection record
if o.httpEnable {
if o.HttpEnable {
h.wg.Add(1)
go func() {
defer h.wg.Done()
handle := wss.NewHttpProxy(wsc, record)
h.httpServer = &http.Server{Addr: o.localHttpAddr, Handler: &handle}
h.httpServer = &http.Server{Addr: o.LocalHttpAddr, Handler: &handle}
if err := h.httpServer.ListenAndServe(); err != nil {
log.Println(err)
}
Expand All @@ -116,7 +118,7 @@ func (h *Handles) startWssocks(o Options) error {
h.wg.Add(1)
go func() {
defer h.wg.Done()
if err := h.cl.ListenAndServe(record, wsc, o.localSocks5Addr, o.httpEnable, func() {
if err := h.cl.ListenAndServe(record, wsc, o.LocalSocks5Addr, o.HttpEnable, func() {
}); err != nil {
log.Println(err)
}
Expand Down
6 changes: 6 additions & 0 deletions extra/go-api/build_archive.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/sh
set -e

# this script build go api into an archive file (static library)

go build --buildmode=c-archive -o libwssocks_go_api.a
56 changes: 56 additions & 0 deletions extra/go-api/wssocks_client_wrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package main

import "C"
import (
"github.com/genshen/wssocks-plugin-ustb/extra"
"github.com/genshen/wssocks-plugin-ustb/plugins/vpn"
"unsafe"
)

// so it would not be destroyed by garbage collection
var handleInstances map[uintptr]*extra.Handles

//export NewClientHandles
func NewClientHandles() uintptr {
hd := new(extra.Handles)
ptr := uintptr(unsafe.Pointer(hd))
if handleInstances == nil {
handleInstances = make(map[uintptr]*extra.Handles)
}
handleInstances[ptr] = hd
return ptr
}

//export StartClientWrapper
func StartClientWrapper(handlesPtr uintptr, localAddr, remoteAddr, httpLocalAddr *C.char,
httpEnable, vpnEnable, vpnForceLogout, vpnHostEncrypt C._Bool,
vpnHostInput, vpnUsername, vpnPassword *C.char) (err *C.char) {
options := extra.Options{
LocalSocks5Addr: C.GoString(localAddr),
RemoteAddr: C.GoString(remoteAddr),
HttpEnable: bool(httpEnable),
LocalHttpAddr: C.GoString(httpLocalAddr),
UstbVpn: vpn.UstbVpn{
Enable: bool(vpnEnable),
ForceLogout: bool(vpnForceLogout),
HostEncrypt: bool(vpnHostEncrypt),
TargetVpn: C.GoString(vpnHostInput),
Username: C.GoString(vpnUsername),
Password: C.GoString(vpnPassword),
},
}
var hp = (*extra.Handles)(unsafe.Pointer(handlesPtr))
if err := hp.StartWssocks(options); err != nil {
return C.CString(err.Error())
}
return C.CString("")
}

//export StopClientWrapper
func StopClientWrapper(handlesPtr uintptr) *C.char {
var hp = (*extra.Handles)(unsafe.Pointer(handlesPtr))
hp.Close()
return C.CString("")
}

func main() {}
123 changes: 123 additions & 0 deletions swiftui-client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
.DS_Store

# Created by .ignore support plugin (hsz.mobi)
### Xcode template
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## User settings
xcuserdata/

## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout

## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3

## Gcc Patch
/*.gcno

### Swift template
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## User settings
xcuserdata/

## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout

## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3

## Obj-C/Swift specific
*.hmap

## App packaging
*.ipa
*.dSYM.zip
*.dSYM

## Playgrounds
timeline.xctimeline
playground.xcworkspace

# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
Packages/
Package.pins
Package.resolved
*.xcodeproj
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm

.build/

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
#
# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace

# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build/

# Accio dependency management
Dependencies/
.accio/

# fastlane
#
# It is recommended to not store the screenshots in the git repo.
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control

fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output

# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode

iOSInjectionProject/

17 changes: 17 additions & 0 deletions swiftui-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# swiftui-client

> wssocks-ustb client for macOS built by swiftui

## How to build
1. build C header file and archive file from go API.
```bash
cd extra/go-api
./build_archive.sh
```

2. Update target’s build settings
In Xcode, set `SWIFT_INCLUDE_PATHS` (Header Search Paths) to `$(SRCROOT)`,
where `$(SRCROOT)` is the same directory as .xcodeproj.
Then `LIBRARY_SEARCH_PATHS` (Library Search Paths) to `$(SRCROOT)/../extra/go-api`.

3. Build application in Xcode.
5 changes: 5 additions & 0 deletions swiftui-client/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module WssocksGoApi {
header "../extra/go-api/libwssocks_go_api.h"
link "wssocks_go_api"
export *
}
52 changes: 52 additions & 0 deletions swiftui-client/wssocks-ustb-client/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// AppDelegate.swift
// wssocks-ustb-client
//
// Created by genshen on 2020/4/30.
// Copyright © 2020 genshen. All rights reserved.
//

import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

var window: NSWindow!
var contentView: ContentView!

func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view that provides the window contents.
contentView = ContentView()
contentView.LoadUserDefaults()
let rootView = contentView.frame(minWidth: 300)

// Create the window and set the content view.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 320, height: 480),
styleMask: [.titled, .closable, .miniaturizable, /*.resizable,*/ .fullSizeContentView],
backing: .buffered, defer: false)
window.title = "wssocks Client"
window.center()
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: rootView)
window.makeKeyAndOrderFront(nil)
}

func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
contentView.StoreUserDefaults()
}

func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
true
}

}


struct AppDelegate_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Loading