This commit is contained in:
wenyifan
2022-08-03 10:30:59 +08:00
commit 60b889a44b
28 changed files with 5366 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
.idea
fastlink
fastlink.exe
session
*.zip
config.conf
+32
View File
@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFbjCCA1agAwIBAgIII1tVz2zmPdEwDQYJKoZIhvcNAQELBQAwTDELMAkGA1UE
BhMCQ04xDTALBgNVBAoTBEV2YW4xDTALBgNVBAsTBEV2YW4xHzAdBgNVBAMTFkV2
YW4gQXNzdXJhbmNlIFJvb3QgQ0EwIBcNMDgwMTAxMDAwMDAwWhgPMjA1MDEyMzEy
MzU5NTlaMEwxCzAJBgNVBAYTAkNOMQ0wCwYDVQQKEwRFdmFuMQ0wCwYDVQQLEwRF
dmFuMR8wHQYDVQQDExZFdmFuIEFzc3VyYW5jZSBSb290IENBMIICIjANBgkqhkiG
9w0BAQEFAAOCAg8AMIICCgKCAgEAq4vXbtUk8y6n3AgH7ApVQ7KOSwymwQnRg0HQ
iZJfamIWYsa1uN7n2/W3tJy82ij0JyIqqiUfTZu8dr6yd12Um7RTN1j32x+3hzSF
+2Hag08vd4ksrHAm61MjZVqdQdi5+EMwR5YlaEYFrgBYsKfo+B4vjFYz2PW7IFlI
SSeHBrtJdKf+pIr0+e2Sp7O91NwAp3JiDChqqyMQbKLaXag0G0o422Mj555L2k6r
E1lNm2JzMKaHqP2Ql/GtCaZXmsD4oRtBfMOr5OkNeGA0lA9OXkZxDXYTGrgGfaY+
kq7ig12eBwa2f09x++aPAYxci8I5fZGCpCPY5siAUpw7r9Tui8d2KOCVDGF4FZ3+
vDnLDPXrrN/2FYHt0p/kNqn9WINLOtfQyk8Ko+zicxjTA9DH5tNyKvxs5NncVXeH
Gjgmto3OAJcRNfu/NOo3IEHRmyOHCtMK/U1oR3ByYsRxc9raKrPI/CBcJQ48XIut
OxdQ+5cK+7IumEXqiAxnvKK1SMBVMnSav7jrfAfq66RNOOTvxng1p2W52dTJIIZB
KcEpzrnMGmLLDba9Zp7v/6PsXYLtwzg0oOJZcnnqOCMz2jMt9o06HFlqYke8Z8Nb
35njmwN4PWyHpEZhbC9VttXqVVD7UaAMStsP2yS2L6Wdt3Af7Mr/kurhLBwK6XOp
H403rdsCAwEAAaNSMFAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9GuH/q/
TaECv2bMT75Rrso+Hu4wCwYDVR0PBAQDAgGGMBEGCWCGSAGG+EIBAQQEAwIABzAN
BgkqhkiG9w0BAQsFAAOCAgEAjsWIGSK2ZJOiCBoH4CqMQNJa2nWOAAY99op8BXRi
Sx8tpbid+mZ6IOIBOY4GLT82lkbDbGmAOXhjDD9pMWYMbxko35MNX3j1/9BAIKU/
W4U5NEIEnWogJJirJjtW+3BGSrbtZyTODCGf2nuJQsXz+YnBAVUNjKILmAVR1bCx
KSXo9YJdrfroHTxk+TB6wewiO8cs5/YlMfKQEyUxTdMOEzRdGvl0dkw6t4346BcS
FqY0tpJ6tvbatVjc+ka//ZxBdKTHWJqkcR0f5g91L0AMllRnAUKAyXIzxUlMB8zN
zfKXhSce2Wk+39kBaDrw4YS6SiJTXVX5ID2Myz/NPDY3upbjPVtDABloF35PcKlr
lekQmYUtN+QoHCb+LEkmHn6/AUdUke7J0Vr1gtqEjqC4f5zPVAx81ZLoBU3FQvb/
DN8QLfdI2/qelfubCRv/XDH+ybhd9aQizKacbcEvpCCLCDkkDqhQyToVoJyeWlGY
s+v2oTcP2x+gPs/2uFGsCQE2U8re9B6BOwYaYaAhoPmHSz4hr7oYc45xop1B+70G
GTGHMHbrbKMPld66dKJQEJ9+mtkJbBrsX/ZHbRHCUjU2yMasSV/S9YHYWWqhC8E+
BSCwrlnMnu4TTxF7uHx0nzWOJFRVfmowsfN4ffHDVoAXfuN7NLc56JsJszVyY0ij
YY8=
-----END CERTIFICATE-----
+32
View File
@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFbjCCA1agAwIBAgIII1tVz2zmPdEwDQYJKoZIhvcNAQELBQAwTDELMAkGA1UE
BhMCQ04xDTALBgNVBAoTBEV2YW4xDTALBgNVBAsTBEV2YW4xHzAdBgNVBAMTFkV2
YW4gQXNzdXJhbmNlIFJvb3QgQ0EwIBcNMDgwMTAxMDAwMDAwWhgPMjA1MDEyMzEy
MzU5NTlaMEwxCzAJBgNVBAYTAkNOMQ0wCwYDVQQKEwRFdmFuMQ0wCwYDVQQLEwRF
dmFuMR8wHQYDVQQDExZFdmFuIEFzc3VyYW5jZSBSb290IENBMIICIjANBgkqhkiG
9w0BAQEFAAOCAg8AMIICCgKCAgEAq4vXbtUk8y6n3AgH7ApVQ7KOSwymwQnRg0HQ
iZJfamIWYsa1uN7n2/W3tJy82ij0JyIqqiUfTZu8dr6yd12Um7RTN1j32x+3hzSF
+2Hag08vd4ksrHAm61MjZVqdQdi5+EMwR5YlaEYFrgBYsKfo+B4vjFYz2PW7IFlI
SSeHBrtJdKf+pIr0+e2Sp7O91NwAp3JiDChqqyMQbKLaXag0G0o422Mj555L2k6r
E1lNm2JzMKaHqP2Ql/GtCaZXmsD4oRtBfMOr5OkNeGA0lA9OXkZxDXYTGrgGfaY+
kq7ig12eBwa2f09x++aPAYxci8I5fZGCpCPY5siAUpw7r9Tui8d2KOCVDGF4FZ3+
vDnLDPXrrN/2FYHt0p/kNqn9WINLOtfQyk8Ko+zicxjTA9DH5tNyKvxs5NncVXeH
Gjgmto3OAJcRNfu/NOo3IEHRmyOHCtMK/U1oR3ByYsRxc9raKrPI/CBcJQ48XIut
OxdQ+5cK+7IumEXqiAxnvKK1SMBVMnSav7jrfAfq66RNOOTvxng1p2W52dTJIIZB
KcEpzrnMGmLLDba9Zp7v/6PsXYLtwzg0oOJZcnnqOCMz2jMt9o06HFlqYke8Z8Nb
35njmwN4PWyHpEZhbC9VttXqVVD7UaAMStsP2yS2L6Wdt3Af7Mr/kurhLBwK6XOp
H403rdsCAwEAAaNSMFAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9GuH/q/
TaECv2bMT75Rrso+Hu4wCwYDVR0PBAQDAgGGMBEGCWCGSAGG+EIBAQQEAwIABzAN
BgkqhkiG9w0BAQsFAAOCAgEAjsWIGSK2ZJOiCBoH4CqMQNJa2nWOAAY99op8BXRi
Sx8tpbid+mZ6IOIBOY4GLT82lkbDbGmAOXhjDD9pMWYMbxko35MNX3j1/9BAIKU/
W4U5NEIEnWogJJirJjtW+3BGSrbtZyTODCGf2nuJQsXz+YnBAVUNjKILmAVR1bCx
KSXo9YJdrfroHTxk+TB6wewiO8cs5/YlMfKQEyUxTdMOEzRdGvl0dkw6t4346BcS
FqY0tpJ6tvbatVjc+ka//ZxBdKTHWJqkcR0f5g91L0AMllRnAUKAyXIzxUlMB8zN
zfKXhSce2Wk+39kBaDrw4YS6SiJTXVX5ID2Myz/NPDY3upbjPVtDABloF35PcKlr
lekQmYUtN+QoHCb+LEkmHn6/AUdUke7J0Vr1gtqEjqC4f5zPVAx81ZLoBU3FQvb/
DN8QLfdI2/qelfubCRv/XDH+ybhd9aQizKacbcEvpCCLCDkkDqhQyToVoJyeWlGY
s+v2oTcP2x+gPs/2uFGsCQE2U8re9B6BOwYaYaAhoPmHSz4hr7oYc45xop1B+70G
GTGHMHbrbKMPld66dKJQEJ9+mtkJbBrsX/ZHbRHCUjU2yMasSV/S9YHYWWqhC8E+
BSCwrlnMnu4TTxF7uHx0nzWOJFRVfmowsfN4ffHDVoAXfuN7NLc56JsJszVyY0ij
YY8=
-----END CERTIFICATE-----
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
packr build -ldflags "-s -w" -trimpath
set GOOS=linux
packr build -ldflags "-s -w" -trimpath
+82
View File
@@ -0,0 +1,82 @@
-----BEGIN CERTIFICATE-----
MIIDyzCCArOgAwIBAgIIcK3jv9ks97kwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UE
BhMCQ04xDTALBgNVBAoTBEV2YW4xDTALBgNVBAsTBEV2YW4xGDAWBgNVBAMTD0V2
YW4gVExTIFJTQSBDQTAeFw0yMjAzMjQwMDAwMDBaFw0yMzAzMjMyMzU5NTlaMEcx
CzAJBgNVBAYTAkNOMQ0wCwYDVQQKEwRFdmFuMQ0wCwYDVQQLEwRFdmFuMRowGAYD
VQQDExFFdmFuIEZhc3RsaW5rIFRMUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALv0Mo21LKTJjFCZcgzWQX5cffJdb2fTObCBv0fkU+0OlsILJYePSD59
/kn59jG9oSwFgFv0Rsr73hg1NRY2+StNslo1eRh8jd0dyQXXaX1cmm3GxrlS0xY5
WEdGYSNrqTEhloBq1bMEmZCAVc7gKemektvOAE0wtZcWILT8B1mo5bkn/ROdhJzW
DBWlZQQRUt5eqxQRVGGllP9k1BUki/ZonA6RdEKzaRl3baUf3MY8tW4S4Sk5yR7W
X8VRZPjCFUFjrFDoFtFCZIziaB6OeTnDmi0+evkPUoUvW4+xFjoWgC/eGYNe2i/k
65Emy5vCmChPrwn3PMDjl+4/cKdM4T0CAwEAAaOBvDCBuTAMBgNVHRMBAf8EAjAA
MB0GA1UdDgQWBBRkwj6Ebx5tnVn21zfPkq/k+WI8aTAfBgNVHSMEGDAWgBTkzE//
yCDVeD30iijpcqJ4vgc95jALBgNVHQ8EBAMCA+gwHQYDVR0lBBYwFAYIKwYBBQUH
AwEGCCsGAQUFBwMCMCoGA1UdEQQjMCGCEmZhc3RsaW5rLmljbG91ZC5jboILKi5p
Y2xvdWQuY24wEQYJYIZIAYb4QgEBBAQDAgbAMA0GCSqGSIb3DQEBCwUAA4IBAQAd
F1m3sw3Ygf8ISoMeaGvMS2qhDiCqZoICy0YEQWuuMowmPVr+6y+dGPbCPCGx/V/+
aD8TH8ZfmlNYz0QYohtWVzsDUdmb/dZkMijFaqWf77QwzA1/ObUUOL3xvE8+8rLD
TvLx7Wg8vVntPnG/3EocW//F+tvoDDE626Moxx02iFxdt7OKkntr5C/CQCIAXSbj
jCzo4GsByGRmGv4jvez1fZ4/MoRcwH19tpoJLEINU9JDm78E0rt9DNKR3f1vPQBO
AR4NKmlZLxPKbhnEgvKbGgIG5R66tHcL4JF4DI/J/bEFK3vWwVfufRA84wKUK07l
w74dNHVmcL3sq9SvK7At
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEhDCCAmygAwIBAgIIUw9sncwT5HcwDQYJKoZIhvcNAQELBQAwTDELMAkGA1UE
BhMCQ04xDTALBgNVBAoTBEV2YW4xDTALBgNVBAsTBEV2YW4xHzAdBgNVBAMTFkV2
YW4gQXNzdXJhbmNlIFJvb3QgQ0EwHhcNMjIwMTAxMDAwMDAwWhcNMzIxMjMxMjM1
OTU5WjBFMQswCQYDVQQGEwJDTjENMAsGA1UEChMERXZhbjENMAsGA1UECxMERXZh
bjEYMBYGA1UEAxMPRXZhbiBUTFMgUlNBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAox2P/00Y8RimWNxKi/iA3ERywf21imyNy+v8d47Bg2iH8PaZ
RAKYya19OkLQOsWFCS6L8/Bx/c/HPZfMOS62ro9IQ6D5UWP0rK0nSd7gvUU63f6K
6ZJ5LR1owAVx0xZ9b+sL89J+VlNuVR8+SjYx2OlOUonk3IPHkvm9WCtFMA2bkHjd
uG2KSJTn4roXr5nVhIi53RnSaiyBlRJ0OeJ2IPgmA/U5v/0Rr2I3YN7NJ/n+3bCO
kNeX/o3qa+C4PoedXfnlIGJyqcc3l6SCSsZ5IFyvQDgE8kuO9UYXk/jFQnYyHsNb
QA/ZiiR2mzQ12eeDxaqZAYYeC0ys/OL7ZvZt5QIDAQABo3EwbzAPBgNVHRMBAf8E
BTADAQH/MB0GA1UdDgQWBBTkzE//yCDVeD30iijpcqJ4vgc95jALBgNVHQ8EBAMC
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBEGCWCGSAGG+EIBAQQE
AwIAxzANBgkqhkiG9w0BAQsFAAOCAgEAPcEmb/L749blVCP5+RDFN+lS78MYQyMT
ZikN3AJP6pV5pTM3uc+zD+sproRslJum7DkeuPn2WltRN3bcB4cemvFMZyx0luFc
XVJ3Gy+wx0L0JexBri5B9iFovZaHxKM0uaBmHDyHfGV6NhsFJWlPL9XQTRQD6EQ4
meWRNpEs+W5RCXMMQ7VqyRLovC4OdbnPkyZv+UGKajGzGPzm6hZfG3bA5TxSFney
ZerpxSnLASkzAe1w5G91RU3dPKPiULJq01l5uv2fy7p5KYDWSqxOrB0KvpZtAVRx
6VbmFEogmG66M2OGEm9ptz4FOh08KsTfcuS3KWiyVjBi/IcqzbOMWkkIrw0SM7Bu
tbgIrS4bbYUFfCJqYsRw0Nfmn1Ndll2sLD3iTqL5kqSaAsI9zGyEn5QPnZCGvx3R
ryAHAI+ImvfFMZjvbZ95++IBJ/7CDYlp25oVd/JBzxq2fpNqO+Z5r4Cg+UFve1uU
c6M1KGeKF15sQi69gkbcUPQpYaxT5+zTag88V0NIwhuGgmaMvvo1vN5O+tziL4B4
HxJNaUJbv2rolJ7stspw8C6L6daP+7qfyIaZONJCGEXt46V4mDH9vV5/JWyhhuSE
rL39I9OzjaUhsooodJwcKUuU1BAzg3oaXxANzEPMILDHo7dPDWkY+JoVa/VW5Huc
2kzz4/hrJdU=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFbjCCA1agAwIBAgIII1tVz2zmPdEwDQYJKoZIhvcNAQELBQAwTDELMAkGA1UE
BhMCQ04xDTALBgNVBAoTBEV2YW4xDTALBgNVBAsTBEV2YW4xHzAdBgNVBAMTFkV2
YW4gQXNzdXJhbmNlIFJvb3QgQ0EwIBcNMDgwMTAxMDAwMDAwWhgPMjA1MDEyMzEy
MzU5NTlaMEwxCzAJBgNVBAYTAkNOMQ0wCwYDVQQKEwRFdmFuMQ0wCwYDVQQLEwRF
dmFuMR8wHQYDVQQDExZFdmFuIEFzc3VyYW5jZSBSb290IENBMIICIjANBgkqhkiG
9w0BAQEFAAOCAg8AMIICCgKCAgEAq4vXbtUk8y6n3AgH7ApVQ7KOSwymwQnRg0HQ
iZJfamIWYsa1uN7n2/W3tJy82ij0JyIqqiUfTZu8dr6yd12Um7RTN1j32x+3hzSF
+2Hag08vd4ksrHAm61MjZVqdQdi5+EMwR5YlaEYFrgBYsKfo+B4vjFYz2PW7IFlI
SSeHBrtJdKf+pIr0+e2Sp7O91NwAp3JiDChqqyMQbKLaXag0G0o422Mj555L2k6r
E1lNm2JzMKaHqP2Ql/GtCaZXmsD4oRtBfMOr5OkNeGA0lA9OXkZxDXYTGrgGfaY+
kq7ig12eBwa2f09x++aPAYxci8I5fZGCpCPY5siAUpw7r9Tui8d2KOCVDGF4FZ3+
vDnLDPXrrN/2FYHt0p/kNqn9WINLOtfQyk8Ko+zicxjTA9DH5tNyKvxs5NncVXeH
Gjgmto3OAJcRNfu/NOo3IEHRmyOHCtMK/U1oR3ByYsRxc9raKrPI/CBcJQ48XIut
OxdQ+5cK+7IumEXqiAxnvKK1SMBVMnSav7jrfAfq66RNOOTvxng1p2W52dTJIIZB
KcEpzrnMGmLLDba9Zp7v/6PsXYLtwzg0oOJZcnnqOCMz2jMt9o06HFlqYke8Z8Nb
35njmwN4PWyHpEZhbC9VttXqVVD7UaAMStsP2yS2L6Wdt3Af7Mr/kurhLBwK6XOp
H403rdsCAwEAAaNSMFAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9GuH/q/
TaECv2bMT75Rrso+Hu4wCwYDVR0PBAQDAgGGMBEGCWCGSAGG+EIBAQQEAwIABzAN
BgkqhkiG9w0BAQsFAAOCAgEAjsWIGSK2ZJOiCBoH4CqMQNJa2nWOAAY99op8BXRi
Sx8tpbid+mZ6IOIBOY4GLT82lkbDbGmAOXhjDD9pMWYMbxko35MNX3j1/9BAIKU/
W4U5NEIEnWogJJirJjtW+3BGSrbtZyTODCGf2nuJQsXz+YnBAVUNjKILmAVR1bCx
KSXo9YJdrfroHTxk+TB6wewiO8cs5/YlMfKQEyUxTdMOEzRdGvl0dkw6t4346BcS
FqY0tpJ6tvbatVjc+ka//ZxBdKTHWJqkcR0f5g91L0AMllRnAUKAyXIzxUlMB8zN
zfKXhSce2Wk+39kBaDrw4YS6SiJTXVX5ID2Myz/NPDY3upbjPVtDABloF35PcKlr
lekQmYUtN+QoHCb+LEkmHn6/AUdUke7J0Vr1gtqEjqC4f5zPVAx81ZLoBU3FQvb/
DN8QLfdI2/qelfubCRv/XDH+ybhd9aQizKacbcEvpCCLCDkkDqhQyToVoJyeWlGY
s+v2oTcP2x+gPs/2uFGsCQE2U8re9B6BOwYaYaAhoPmHSz4hr7oYc45xop1B+70G
GTGHMHbrbKMPld66dKJQEJ9+mtkJbBrsX/ZHbRHCUjU2yMasSV/S9YHYWWqhC8E+
BSCwrlnMnu4TTxF7uHx0nzWOJFRVfmowsfN4ffHDVoAXfuN7NLc56JsJszVyY0ij
YY8=
-----END CERTIFICATE-----
+189
View File
@@ -0,0 +1,189 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"github.com/gobuffalo/packr"
"io"
"log"
"math/rand"
"net/http"
"os"
"os/signal"
"time"
)
func main() {
Logger = log.New(io.Writer(os.Stdout), "", log.Lshortfile|log.LstdFlags)
rand.Seed(time.Now().Unix())
var port string
var address string
flag.StringVar(&port, "port", "1443", "serve port")
flag.StringVar(&address, "listen", "", "listen address")
flag.StringVar(&configPath, "config", "config.conf", "config path")
flag.Parse()
fastLinkService = new(FastLinkService)
ReadConfig()
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, os.Kill)
go func() {
<-c //阻塞直至有信号传入
Logger.Println("Saving config")
SaveConfig()
Logger.Println("Save config done,exit now.")
os.Exit(0)
}()
go func() {
ticker := time.NewTicker(time.Minute)
for range ticker.C {
<-ticker.C
fastLinkService.KillAloneSignalSession()
fastLinkService.KillExpiredToken()
SaveConfig()
Logger.Println("Saving config")
ticker.Reset(time.Minute)
}
}()
http.HandleFunc("/admin/config", configHandler)
http.HandleFunc("/admin/addUser", addUserHandler)
http.HandleFunc("/admin/editUser", editUserHandler)
http.HandleFunc("/admin/removeUser", removeUserHandler)
http.HandleFunc("/admin/kickUser", kickUserHandler)
http.HandleFunc("/admin/removeDevice", removeDeviceHandler)
http.HandleFunc("/admin/removeCustomName", removeCustomNameHandler)
http.HandleFunc("/socket.io/", socketHandler)
http.HandleFunc("/fastLink/shareUrl/connect/check", checkHandler)
http.HandleFunc("/fastLink/device/deviceVerificationType", deviceVerificationTypeHandler)
http.HandleFunc("/fastLink/config/idTransfer", idTransferHandler)
http.HandleFunc("/fastLink/stream/record/close", closeHandler)
http.HandleFunc("/fastLink/user/loginForApp", loginForAppHandler)
http.HandleFunc("/fastLink/device/list", appListDeviceHandler)
http.HandleFunc("/fastLink/user/logout", logoutHandler)
http.HandleFunc("/fastLink/user/register", registerHandler)
http.HandleFunc("/fastLink/code/send", sendCodeHandler)
box := packr.NewBox("web")
http.Handle("/", http.FileServer(box))
err := http.ListenAndServeTLS(address+":"+port, "cert.crt", "private.key", nil)
//套nginx或Caddy可直接使用Http
//err := http.ListenAndServe(address+":"+port, nil)
if err != nil {
fmt.Print(err)
}
}
func socketHandler(w http.ResponseWriter, r *http.Request) {
clientType := r.FormValue("clientType")
if clientType == CLIENT_TYPE_CPP || clientType == CLIENT_TYPE_WEB {
signalHandler(w, r)
} else {
serviceHandler(w, r)
}
}
func configHandler(w http.ResponseWriter, r *http.Request) {
marshal, _ := json.Marshal(fastLinkService)
w.Write(marshal)
}
func addUserHandler(w http.ResponseWriter, r *http.Request) {
user := r.FormValue("user")
pass := r.FormValue("pass")
if user == "" {
w.Write([]byte("user is empty"))
return
}
if pass == "" {
w.Write([]byte("pass is empty"))
return
}
exist := fastLinkService.CheckUserExist(user)
if exist {
w.Write([]byte("user exist"))
return
}
fastLinkService.AddUser(user, pass)
w.Write([]byte("success"))
}
func editUserHandler(w http.ResponseWriter, r *http.Request) {
user := r.FormValue("user")
pass := r.FormValue("pass")
if user == "" {
w.Write([]byte("user is empty"))
return
}
if pass == "" {
w.Write([]byte("pass is empty"))
return
}
exist := fastLinkService.CheckUserExist(user)
if !exist {
w.Write([]byte("user not exist"))
return
}
fastLinkService.EditUser(user, pass)
w.Write([]byte("success"))
}
func removeUserHandler(w http.ResponseWriter, r *http.Request) {
user := r.FormValue("user")
if user == "" {
w.Write([]byte("user is empty"))
return
}
fastLinkService.removeUser(user)
fastLinkService.removeDevicesByUser(user)
fastLinkService.removeTokenByUser(user)
w.Write([]byte("success"))
}
func kickUserHandler(w http.ResponseWriter, r *http.Request) {
user := r.FormValue("user")
if user == "" {
w.Write([]byte("user is empty"))
return
}
fastLinkService.removeTokenByUser(user)
w.Write([]byte("success"))
}
func removeDeviceHandler(w http.ResponseWriter, r *http.Request) {
deviceNo := r.FormValue("deviceNo")
if deviceNo == "" {
w.Write([]byte("deviceNo is empty"))
return
}
device := fastLinkService.GetDeviceByNo(deviceNo)
if device != nil {
user := device.BelongUser
fastLinkService.removeDevice(deviceNo)
if user != "" {
notifyDeviceChange(user)
}
}
w.Write([]byte("success"))
}
func removeCustomNameHandler(w http.ResponseWriter, r *http.Request) {
deviceNo := r.FormValue("deviceNo")
if deviceNo == "" {
w.Write([]byte("deviceNo is empty"))
return
}
device := fastLinkService.GetDeviceByNo(deviceNo)
if device != nil {
device.CustomName = ""
if device.BelongUser != "" {
notifyDeviceChange(device.BelongUser)
}
}
w.Write([]byte("success"))
}
+627
View File
@@ -0,0 +1,627 @@
package main
import (
"github.com/beevik/guid"
"github.com/gorilla/websocket"
"math/rand"
"strconv"
"strings"
"sync"
"time"
)
type SessionInfo struct {
SessionId string `json:"sessionId"`
DeviceNo string `json:"deviceNo"`
ClientType string `json:"clientType"`
Guid string `json:"guid"`
WsConn *websocket.Conn `json:"-"`
}
type SignalSessionInfo struct {
Token string `json:"token"`
RelateDeviceId int `json:"relateDeviceId"`
RelateDeviceNo string `json:"relateDeviceNo"`
StreamUser string `json:"streamUser"`
StreamToken string `json:"streamToken"`
CreateTime time.Time `json:"createTime"`
Active bool `json:"active"`
Guid string `json:"guid"`
WsConn *websocket.Conn `json:"-"`
}
type UserInfo struct {
Name string `json:"name"`
Pass string `json:"pass"`
}
type TokenInfo struct {
Token string `json:"token"`
Type string `json:"type"`
User string `json:"user"`
SessionId string `json:"sessionId"`
LastActive time.Time `json:"lastActive"`
}
type DeviceInfo struct {
DeviceNo string `json:"deviceNo"`
DeviceId int `json:"deviceId"`
DeviceName string `json:"deviceName"`
IdentificationCode string `json:"identificationCode"`
VerificationCode string `json:"verificationCode"`
ShareRand string `json:"shareRand"`
BelongUser string `json:"belongUser"`
Visible bool `json:"visible"`
TwoStepPass string `json:"twoStepPass"`
VerificationType int `json:"verificationType"`
CustomName string `json:"customName"`
Online bool `json:"-"`
}
type FastLinkService struct {
sessionLock sync.Mutex
deviceLock sync.Mutex
userLock sync.Mutex
tokenLock sync.Mutex
signalLock sync.Mutex
Sessions []*SessionInfo `json:"sessions"`
Users []*UserInfo `json:"users"`
Devices []*DeviceInfo `json:"devices"`
Tokens []*TokenInfo `json:"tokens"`
SignalSessions []*SignalSessionInfo `json:"signalSessions"`
}
func (f *FastLinkService) FillUsers(users []*UserInfo) {
f.userLock.Lock()
defer f.userLock.Unlock()
f.Users = users
}
func (f *FastLinkService) FillDevices(devices []*DeviceInfo) {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
f.Devices = devices
}
func (f *FastLinkService) FillTokens(tokens []*TokenInfo) {
f.tokenLock.Lock()
defer f.tokenLock.Unlock()
f.Tokens = tokens
}
func (f *FastLinkService) NewSession(deviceNo string, sessionId string, sessionGuid string, clientType string, wsConn *websocket.Conn) {
f.sessionLock.Lock()
defer f.sessionLock.Unlock()
for _, session := range f.Sessions {
if session.SessionId == sessionId {
session.DeviceNo = deviceNo
session.WsConn = wsConn
session.ClientType = clientType
session.Guid = sessionGuid
return
}
}
f.Sessions = append(f.Sessions, &SessionInfo{
SessionId: sessionId,
DeviceNo: deviceNo,
WsConn: wsConn,
ClientType: clientType,
Guid: sessionGuid,
})
}
func (f *FastLinkService) SetOnlineStatus(deviceNo string) {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
session := f.GetSession(deviceNo, CLIENT_TYPE_FASTLINK_SERVICE)
for _, device := range f.Devices {
if device.DeviceNo == deviceNo {
if session == nil {
device.Online = false
} else {
device.Online = true
}
return
}
}
}
func (f *FastLinkService) GetSession(deviceNo string, clientType string) *SessionInfo {
f.sessionLock.Lock()
defer f.sessionLock.Unlock()
for _, session := range f.Sessions {
if session.DeviceNo == deviceNo && session.ClientType == clientType {
return session
}
}
return nil
}
func (f *FastLinkService) GetSessionsByUser(user string, clientType string) []*SessionInfo {
f.sessionLock.Lock()
defer f.sessionLock.Unlock()
var result []*SessionInfo
for _, session := range f.Sessions {
device := f.GetDeviceByNo(session.DeviceNo)
if device != nil && device.BelongUser == user && session.ClientType == clientType {
result = append(result, session)
}
}
return result
}
func (f *FastLinkService) PrepareSignalSession(token string, relateDeviceId int, relateDeviceNo string, streamToken string, streamUser string) {
f.signalLock.Lock()
defer f.signalLock.Unlock()
f.SignalSessions = append(f.SignalSessions, &SignalSessionInfo{
Token: token,
RelateDeviceId: relateDeviceId,
RelateDeviceNo: relateDeviceNo,
StreamToken: streamToken,
StreamUser: streamUser,
CreateTime: time.Now().In(TimeLocation),
})
}
func (f *FastLinkService) NewSignalSession(token string, sessionGuid string, wsConn *websocket.Conn) {
f.signalLock.Lock()
defer f.signalLock.Unlock()
for _, session := range f.SignalSessions {
if session.Token == token {
session.WsConn = wsConn
session.Active = true
session.Guid = sessionGuid
return
}
}
f.SignalSessions = append(f.SignalSessions, &SignalSessionInfo{
Token: token,
Active: true,
WsConn: wsConn,
Guid: sessionGuid,
})
}
func (f *FastLinkService) KillAloneSignalSession() {
f.signalLock.Lock()
defer f.signalLock.Unlock()
var tmp []*SignalSessionInfo
for _, session := range f.SignalSessions {
if session.Active == false && session.RelateDeviceNo != "" {
if time.Now().In(TimeLocation).Sub(session.CreateTime.In(TimeLocation)).Seconds() > 120 {
continue
}
}
tmp = append(tmp, session)
}
f.SignalSessions = tmp
}
func (f *FastLinkService) RemoveSession(sessionId string, sessionGuid string) {
f.sessionLock.Lock()
defer f.sessionLock.Unlock()
var tmp []*SessionInfo
needRemove := false
for _, session := range f.Sessions {
if session.SessionId == sessionId && session.Guid == sessionGuid {
needRemove = true
break
}
}
if needRemove {
for _, session := range f.Sessions {
if session.SessionId != sessionId {
tmp = append(tmp, session)
}
}
f.Sessions = tmp
}
}
func (f *FastLinkService) RemoveSignalSession(token string, sessionGuid string) {
f.signalLock.Lock()
defer f.signalLock.Unlock()
var tmp []*SignalSessionInfo
needRemove := false
for _, session := range f.SignalSessions {
if session.Token == token && session.Guid == sessionGuid {
needRemove = true
break
}
}
if needRemove {
for _, session := range f.SignalSessions {
if session.Token != token {
tmp = append(tmp, session)
}
}
f.SignalSessions = tmp
}
}
func (f *FastLinkService) GetSignalSession(token string) *SignalSessionInfo {
f.signalLock.Lock()
defer f.signalLock.Unlock()
for _, session := range f.SignalSessions {
if session.Token == token {
return session
}
}
return nil
}
func (f *FastLinkService) GetSignalSessionByDeviceId(deviceId int) []*SignalSessionInfo {
f.signalLock.Lock()
defer f.signalLock.Unlock()
var result []*SignalSessionInfo
for _, session := range f.SignalSessions {
if session.RelateDeviceId == deviceId {
result = append(result, session)
}
}
return result
}
func (f *FastLinkService) AddDevice(deviceNo string, deviceName string) *DeviceInfo {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
for _, device := range f.Devices {
if device.DeviceNo == deviceNo {
device.DeviceName = deviceName
return device
}
}
newDeviceId := 0
for i := LastDeviceId + 1; i < 10000; i++ {
exist := false
for _, device := range f.Devices {
if device.DeviceId == i {
exist = true
break
}
}
if !exist {
newDeviceId = i
LastDeviceId = i
break
}
}
identificationCode := RandNum(9)
for {
exist := false
for _, device := range f.Devices {
if device.IdentificationCode == identificationCode {
exist = true
break
}
}
if exist {
identificationCode = RandNum(9)
} else {
break
}
}
device := &DeviceInfo{
DeviceNo: deviceNo,
DeviceId: newDeviceId,
DeviceName: deviceName,
IdentificationCode: identificationCode,
VerificationCode: RandStr(6),
ShareRand: "1" + RandNum(9),
BelongUser: "",
Online: true,
Visible: true,
}
f.Devices = append(f.Devices, device)
return device
}
func (f *FastLinkService) RefreshDeviceVerificationCode(deviceNo string) *DeviceInfo {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
for _, device := range f.Devices {
if device.DeviceNo == deviceNo {
device.VerificationCode = RandStr(6)
device.ShareRand = "1" + RandNum(9)
return device
}
}
return nil
}
func (f *FastLinkService) GetDeviceByNo(deviceNo string) *DeviceInfo {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
for _, device := range f.Devices {
if device.DeviceNo == deviceNo {
return device
}
}
return nil
}
func (f *FastLinkService) removeDevice(deviceNo string) {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
var tmp []*DeviceInfo
for _, device := range f.Devices {
if device.DeviceNo != deviceNo {
tmp = append(tmp, device)
}
}
f.Devices = tmp
}
func (f *FastLinkService) GetDeviceByIdentificationCode(identificationCode string) *DeviceInfo {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
for _, device := range f.Devices {
if device.IdentificationCode == identificationCode {
return device
}
}
return nil
}
func (f *FastLinkService) GetDeviceById(deviceId int) *DeviceInfo {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
for _, device := range f.Devices {
if device.DeviceId == deviceId {
return device
}
}
return nil
}
func (f *FastLinkService) AddUser(username string, password string) *UserInfo {
f.userLock.Lock()
defer f.userLock.Unlock()
for _, user := range f.Users {
if user.Name == username {
return user
}
}
u := &UserInfo{
Name: username,
Pass: password,
}
f.Users = append(f.Users, u)
return u
}
func (f *FastLinkService) Login(username string, password string, deviceId int) string {
f.userLock.Lock()
defer f.userLock.Unlock()
succ := false
for _, user := range f.Users {
if user.Name == username && user.Pass == password {
succ = true
break
}
}
if !succ {
return ""
}
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
for _, device := range f.Devices {
if device.DeviceId == deviceId {
device.BelongUser = username
}
}
return f.NewToken(username, TOKEN_TYPE_PC)
}
func (f *FastLinkService) CheckUser(username string, password string) bool {
f.userLock.Lock()
defer f.userLock.Unlock()
for _, user := range f.Users {
if user.Name == username && user.Pass == password {
return true
}
}
return false
}
func (f *FastLinkService) CheckUserExist(username string) bool {
f.userLock.Lock()
defer f.userLock.Unlock()
for _, user := range f.Users {
if user.Name == username {
return true
}
}
return false
}
func (f *FastLinkService) EditUser(username string, password string) {
f.userLock.Lock()
defer f.userLock.Unlock()
for _, user := range f.Users {
if user.Name == username {
user.Pass = password
}
}
}
func (f *FastLinkService) removeUser(username string) {
f.userLock.Lock()
defer f.userLock.Unlock()
var tmp []*UserInfo
for _, user := range f.Users {
if user.Name != username {
tmp = append(tmp, user)
}
}
f.Users = tmp
}
func (f *FastLinkService) removeDevicesByUser(username string) {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
var tmp []*DeviceInfo
for _, device := range f.Devices {
if device.BelongUser != username {
tmp = append(tmp, device)
}
}
f.Devices = tmp
}
func (f *FastLinkService) removeTokenByUser(username string) {
f.tokenLock.Lock()
defer f.tokenLock.Unlock()
var tmp []*TokenInfo
for _, token := range f.Tokens {
if token.User != username {
tmp = append(tmp, token)
}
}
f.Tokens = tmp
}
func (f *FastLinkService) GetUserByToken(token string) string {
f.tokenLock.Lock()
defer f.tokenLock.Unlock()
for _, info := range f.Tokens {
if info.Token == token {
return info.User
}
}
return ""
}
func (f *FastLinkService) GetDeviceByToken(token string) []*DeviceInfo {
user := f.GetUserByToken(token)
if user == "" {
return []*DeviceInfo{}
}
f.RenewToken(token)
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
var dList []*DeviceInfo
for _, device := range f.Devices {
if device.BelongUser == user && device.Visible {
dList = append(dList, device)
}
}
return dList
}
func (f *FastLinkService) NewToken(username string, tokenType string) string {
f.tokenLock.Lock()
defer f.tokenLock.Unlock()
token := guid.New().String()
f.Tokens = append(f.Tokens, &TokenInfo{
Token: token,
User: username,
Type: tokenType,
LastActive: time.Now().In(TimeLocation),
})
return token
}
func (f *FastLinkService) BindSessionToToken(sessionId string, token string) {
f.tokenLock.Lock()
defer f.tokenLock.Unlock()
for _, info := range f.Tokens {
if info.Token == token {
info.SessionId = sessionId
return
}
}
}
func (f *FastLinkService) GetTokenBySession(sessionId string) string {
f.tokenLock.Lock()
defer f.tokenLock.Unlock()
for _, info := range f.Tokens {
if info.SessionId == sessionId {
return info.Token
}
}
return ""
}
func (f *FastLinkService) RemoveToken(token string) {
f.tokenLock.Lock()
defer f.tokenLock.Unlock()
var tmp []*TokenInfo
for _, info := range f.Tokens {
if info.Token != token {
tmp = append(tmp, info)
}
}
f.Tokens = tmp
}
func (f *FastLinkService) RenewToken(token string) {
f.tokenLock.Lock()
defer f.tokenLock.Unlock()
for _, info := range f.Tokens {
if info.Token == token {
info.LastActive = time.Now().In(TimeLocation)
}
}
}
func (f *FastLinkService) KillExpiredToken() {
f.tokenLock.Lock()
defer f.tokenLock.Unlock()
var tmp []*TokenInfo
for _, info := range f.Tokens {
life := TOKEN_APP_MAX_LIFE
if info.Type == "pc" {
life = TOKEN_PC_MAX_LIFE
}
if time.Now().In(TimeLocation).Sub(info.LastActive.In(TimeLocation)).Seconds() <= float64(life) {
tmp = append(tmp, info)
} else {
Logger.Println("Remove expired token:" + info.Token + ", LastActive time=" + info.LastActive.In(TimeLocation).Format("2006-01-02 15:04:05"))
}
}
f.Tokens = tmp
}
func (f *FastLinkService) CheckWebLogin(deviceNo string, random string) int {
f.deviceLock.Lock()
defer f.deviceLock.Unlock()
for _, device := range f.Devices {
if device.DeviceNo == deviceNo {
if device.ShareRand == random {
return 0
} else {
return 1
}
}
}
return 2
}
func RandNum(length int) string {
var result string
for i := 0; i < length; i++ {
result += strconv.Itoa(rand.Intn(9))
}
return result
}
func RandStr(length int) string {
str := "0123456789abcdefghijklmnopqrstuvwxyz"
bytes := []byte(str)
result := []byte{}
rand.Seed(time.Now().UnixNano() + int64(rand.Intn(100)))
for i := 0; i < length; i++ {
result = append(result, bytes[rand.Intn(len(bytes))])
}
return string(result)
}
func GenShortGUID() string {
return strings.ReplaceAll(guid.New().String(), "-", "")
}
+54
View File
@@ -0,0 +1,54 @@
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/beevik/guid"
"testing"
)
func TestName(t *testing.T) {
var params *MessageResponse
params = &MessageResponse{
Id: "fsdgsdgsdg",
Method: "Add",
Result: &AddDeviceResponse{
Code: 0,
DeviceId: 453565,
},
}
response := makeMessageResponse("fff", params)
fmt.Println(string(response))
}
func TestName2(t *testing.T) {
fmt.Println(guid.New().String())
}
func TestName3(t *testing.T) {
var items []interface{}
json.Unmarshal([]byte("[\"owt-message\",{\"data\":\"{\\\"type\\\":\\\"chat-reset\\\"}\",\"from\":\"5ff5fce328f74b8f964fd282f0c4e1b8\",\"to\":\"b5f5ceab-d964-5f41-a7b7-e16f197f0692\"}]"), &items)
s := items[1].(map[string]interface{})["data"].(string)
fmt.Println(s)
}
func TestName4(t *testing.T) {
toString := base64.StdEncoding.EncodeToString([]byte("b5f5ceab-d964-5f41-a7b7-e16f197f0692"))
fmt.Println(toString)
decodeString, _ := base64.StdEncoding.DecodeString("YjVmNWNlYWItZDk2NC01ZjQxLWE3YjctZTE2ZjE5N2YwNjky")
fmt.Println(string(decodeString))
}
func TestAAA(t *testing.T) {
str := "{\"id\":\"182ade4f-b515-8e4f-bf19-4d2b10f651a5\",\"method\":\"NotifyClientOffline\",\"params\":{\"clientIds\":[\"7bc127b80aea4ab598dd35ac589752e1\"],\"reason\":3}}"
var item MessageInfo
json.Unmarshal([]byte(str), &item)
uuu := item.Params.(map[string]interface{})["clientIds"].([]interface{})
for _, i2 := range uuu {
fmt.Println(i2)
}
}
+94
View File
@@ -0,0 +1,94 @@
package main
import (
"encoding/json"
"io/ioutil"
"log"
"os"
"time"
)
const CLIENT_TYPE_CPP = "cpp"
const CLIENT_TYPE_WEB = "Web"
const CLIENT_TYPE_FASTLINK_UI = "fastlink_ui"
const CLIENT_TYPE_FASTLINK_SERVICE = "fastlink_service"
const TOKEN_TYPE_APP = "app"
const TOKEN_TYPE_PC = "pc"
const TOKEN_PC_MAX_LIFE = 3600
const TOKEN_APP_MAX_LIFE = 86400
const WEB_URL = "https://fastlink.evan.run/"
var (
Logger *log.Logger
fastLinkService *FastLinkService
globalConfig = GlobalConfig{
SignalServer: "https://fastlink.evan.run",
StunServers: []string{"stun:106.54.197.45:3478"},
TurnServers: []TurnServer{{
Addr: "turn:106.54.197.45:3478",
Password: "evanturn",
UserName: "evan",
}, {
Addr: "turn:221.229.220.67:3478",
Password: "evanturn",
UserName: "evan",
}},
}
configPath string
LastDeviceId = 0
TimeLocation *time.Location = time.FixedZone("CST", 8*3600)
)
type GlobalConfig struct {
SignalServer string `json:"signalServer"`
StunServers []string `json:"stunServers"`
TurnServers []TurnServer `json:"turnServers"`
}
type TurnServer struct {
Addr string `json:"addr"`
Password string `json:"password"`
UserName string `json:"userName"`
}
type ConfigData struct {
LastDeviceId int `json:"lastDeviceId"`
Users []*UserInfo `json:"users"`
Devices []*DeviceInfo `json:"devices"`
Tokens []*TokenInfo `json:"tokens"`
}
func SaveConfig() {
config := &ConfigData{
Users: fastLinkService.Users,
Devices: fastLinkService.Devices,
Tokens: fastLinkService.Tokens,
LastDeviceId: LastDeviceId,
}
marshal, _ := json.Marshal(config)
ioutil.WriteFile(configPath, marshal, 0777)
}
func ReadConfig() {
b, _ := exists(configPath)
if b {
configData, _ := ioutil.ReadFile(configPath)
var config *ConfigData
json.Unmarshal(configData, &config)
fastLinkService.FillUsers(config.Users)
fastLinkService.FillDevices(config.Devices)
fastLinkService.FillTokens(config.Tokens)
LastDeviceId = config.LastDeviceId
}
}
func exists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return true, err
}
+16
View File
@@ -0,0 +1,16 @@
module fastlink
go 1.18
require (
github.com/beevik/guid v0.0.0-20170504223318-d0ea8faecee0
github.com/gobuffalo/packr v1.30.1
github.com/gorilla/websocket v1.5.0
)
require (
github.com/gobuffalo/envy v1.7.0 // indirect
github.com/gobuffalo/packd v0.3.0 // indirect
github.com/joho/godotenv v1.3.0 // indirect
github.com/rogpeppe/go-internal v1.3.0 // indirect
)
+73
View File
@@ -0,0 +1,73 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beevik/guid v0.0.0-20170504223318-d0ea8faecee0 h1:oLd/YLOTOgA4D4aAUhIE8vhl/LAP1ZJrj0mDQpl7GB8=
github.com/beevik/guid v0.0.0-20170504223318-d0ea8faecee0/go.mod h1:XzXWuOd1wJ63MtICHh5+PnvCuxsB/d58T8TswEhI/9I=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=
github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk=
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
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/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+3
View File
@@ -0,0 +1,3 @@
106.54.197.45 fastlink.icloud.cn
106.54.197.45 signalserver.icloud.cn
127.0.0.1 datapolaris.shunwang.com
+27
View File
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAu/QyjbUspMmMUJlyDNZBflx98l1vZ9M5sIG/R+RT7Q6Wwgsl
h49IPn3+Sfn2Mb2hLAWAW/RGyvveGDU1Fjb5K02yWjV5GHyN3R3JBddpfVyabcbG
uVLTFjlYR0ZhI2upMSGWgGrVswSZkIBVzuAp6Z6S284ATTC1lxYgtPwHWajluSf9
E52EnNYMFaVlBBFS3l6rFBFUYaWU/2TUFSSL9micDpF0QrNpGXdtpR/cxjy1bhLh
KTnJHtZfxVFk+MIVQWOsUOgW0UJkjOJoHo55OcOaLT56+Q9ShS9bj7EWOhaAL94Z
g17aL+TrkSbLm8KYKE+vCfc8wOOX7j9wp0zhPQIDAQABAoIBAQCG2JVoe8Jy27MS
pHRh51oHuX4W45gpCi9KhlvgzVy1KBFbWDntvwua4jQNiQtr9lvqxGuqDWC5Auj9
vza+IGS1/8Fk3RZrTflN2a++xCSH72dQORucHGMbf7rpMAJDMlupxyo+Kef1zugJ
9zkY+lS3qrA8iNhIiRjPM+31SxhO5xW1XLP8lRi8N5eC3wzp0J0UMWfd+JN+H2Ew
rgWNuJ5nmsNq59ZQ9oXNzLvyLmHZIFMrU9hrmSj5qZF8MSsLuzd61Z0Pvs3hHS6u
70jjREn9X21UdKezU5c3pOFBG95HR/6t/MHXJzYQ3zT4eV8RwesPn7Hsn2PzNtqM
oq7k4T+BAoGBAOomjDmfU0O/bWzbNaFkUdgdF2hyu72Q15icMxiytSYjramjiISD
LVKgxG5Ryk5N+42zV6iEa0AIf7PI9YhsHZphJ5xCaayVjeIpXetUrFONMBrJk04j
6HJ/7sZQG0EQnC43tcxCfgScnMiC7rNg2cBGdcA3H7AXHs0p1jN95HldAoGBAM1+
F0coYuY+PT8L+CAiUrf23fNKEjnVkyZWfaffWCo4RtcvnG9nS3eKqHU+y5yeFSwL
HvIxjr+xM7d1eHdYdyQ/GdgLxbE/aDh43E3zeq6QdTuPoOUVbII2zv4iI+LEbKYk
oc34SlxHp5qBq4+Y1D9Q4QpjTrfJXstIJGDJxylhAoGAOu4EsKPmotBUy+bHspy6
9Hct4v2tPmJrwF7fhUHE0Zp9JIqh2yfgikEn7tPq5JY/z0PpteHN1EnPSgIzuWfs
c2QsQel9CxCAqwDaQFYJIOYRy0wcJLho0hhckdCra06w3/jpakT5zlNUKiq5xK+F
XhzdmcjF0t2exOfYnxD6JYkCgYEAlWHmVio7yxjPuTdgRyvsaiOiMaxVF4n1ENer
PRAVrYt/pArOdAXpTJuV3rWpms8ooP3sny/7j8qnx+QzkL7UzZq5lN7p9fIcN4FU
1a38L06Aiq3czuwGF5r0WrZC1CTqvtS+c1bd57uHUcCWESuOkACht8V9ggl3SdvF
5j6I88ECgYAkmL0vnZyQyt3oGvr0bGdSfrTqtkx0e2XZR9ysu3KnMEkjWQOndnag
Vo9bG2zzBnY8D3tXFWJIpt8M9PBWW7EZiWLac/N8JwtcktcfcQg40wKSCUvQpwKx
LWh0V+LWMdMgGrRU2NeYFENoqyiMHeh8z79eBl0SJJMHITrnGch6kg==
-----END RSA PRIVATE KEY-----
+168
View File
@@ -0,0 +1,168 @@
package main
type MessageInfo struct {
Id string `json:"id"`
Method string `json:"method"`
Params interface{}
}
type AddDeviceParam struct {
DeviceNo string `json:"deviceNo"`
DeviceName string `json:"deviceName"`
}
type MessageResponse struct {
Id string `json:"id"`
Method string `json:"method"`
Result interface{} `json:"result"`
}
type MessageErrorResponse struct {
Error *ErrorResponse `json:"error"`
Id string `json:"id"`
Method string `json:"method"`
Result interface{} `json:"result"`
}
type ErrorResponse struct {
Code int `json:"code"`
Message string `json:"message"`
}
type AddDeviceResponse struct {
Code int `json:"code"`
DeviceId int `json:"deviceId"`
}
type CheckVersionResponse struct {
Code int `json:"code"`
DownloadUrl string `json:"downloadUrl"`
IsUpdate bool `json:"isUpdate"`
NewVersion string `json:"newVersion"`
}
type GetDeviceRemoteControlInfoParam struct {
DeviceId int `json:"deviceId"`
DeviceNo string `json:"deviceNo"`
}
type GetDeviceRemoteControlInfoResponse struct {
Code int `json:"code"`
DeviceId int `json:"deviceId"`
IdentificationCode string `json:"identificationCode"`
ShareUrl string `json:"shareUrl"`
VerificationCode string `json:"verificationCode"`
}
type GetFileTransferConfigResponse struct {
Code int `json:"code"`
DownloadSpeedRatio int `json:"downloadSpeedRatio"`
UploadSpeedRatio int `json:"uploadSpeedRatio"`
}
type GetTurnTransferConfigResponse struct {
Code int `json:"code"`
VideoBitrate int `json:"videoBitrate"`
}
type LoginParam struct {
PhoneNo string `json:"phoneNo"`
Password string `json:"password"`
DeviceId int `json:"deviceId"`
}
type LoginResponse struct {
Code int `json:"code"`
Token string `json:"token"`
}
type GetDeviceResponse struct {
Code int `json:"code"`
Devices []*DeviceResponse `json:"devices"`
}
type DeviceResponse struct {
DeviceId int `json:"deviceId"`
DeviceName string `json:"deviceName"`
DeviceNo string `json:"deviceNo"`
OnlineState int `json:"onlineState"`
}
type StartRemoteControlParam struct {
Type int `json:"type"`
Token string `json:"token"`
RemoteDeviceId int `json:"remoteDeviceId"`
RemoteIdentificationCode string `json:"remoteIdentificationCode"`
RemoteVerificationCode string `json:"remoteVerificationCode"`
VerificationType int `json:"verificationType"`
UserName string `json:"userName"`
Password string `json:"password"`
}
type StartRemoteControlResponse struct {
Code int `json:"code"`
StreamingConfig StreamingConfig `json:"streamingConfig"`
}
type RemoteStartRemoteControlResponse struct {
Id string `json:"id"`
Method string `json:"method"`
Params RemoteStreamingConfig `json:"params"`
}
type NotifyResponse struct {
Id string `json:"id"`
Method string `json:"method"`
Params interface{} `json:"params"`
}
type EmptyObj struct {
}
type StreamingConfig struct {
ClientId string `json:"clientId"`
ClientIds []string `json:"clientIds"`
ServiceId string `json:"serviceId"`
SignalServer string `json:"signalServer"`
StunAddrs []string `json:"stunAddrs"`
Token string `json:"token"`
TurnAddrs []TurnServer `json:"turnAddrs"`
}
type RemoteStreamingConfig struct {
ClientId string `json:"clientId"`
SignalServer string `json:"signalServer"`
StunAddrs []string `json:"stunAddrs"`
Token string `json:"token"`
TurnAddrs []TurnServer `json:"turnAddrs"`
}
type GetDeviceVerificationTypeResponse struct {
Code int `json:"code"`
VerificationType int `json:"verificationType"`
}
type GetOnlineUsersResponse struct {
Code int `json:"code"`
DeviceId int `json:"deviceId"`
Users []OnlineUser `json:"users"`
}
type OnlineUser struct {
ClientId string `json:"clientId"`
ClientOS string `json:"clientOS"`
UserName string `json:"userName"`
VisitTime string `json:"visitTime"`
}
type SimpleResponse struct {
Code int `json:"code"`
}
type DeleteDeviceResponse struct {
Code int `json:"code"`
DeviceId int `json:"deviceId"`
}
type ForceClientOfflineParam struct {
ClientIds []string `json:"clientIds"`
Reason int `json:"reason"`
}
+660
View File
@@ -0,0 +1,660 @@
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/beevik/guid"
"github.com/gorilla/websocket"
"net/http"
"strings"
"time"
)
var (
upgrader = websocket.Upgrader{
//允许跨域访问
CheckOrigin: func(r *http.Request) bool {
return true
},
EnableCompression: false,
}
)
func serviceHandler(w http.ResponseWriter, r *http.Request) {
deviceNo := r.FormValue("deviceNo")
sessionId := r.FormValue("session_id")
clientType := r.FormValue("client_type")
wsConn, upgradeErr := upgrader.Upgrade(w, r, w.Header())
if upgradeErr != nil {
return
}
defer func() {
if reco := recover(); reco != any(nil) {
fmt.Printf("Service Runtime error caught: %v", reco)
}
}()
tokenOfSession := fastLinkService.GetTokenBySession(sessionId)
sessionGuid := guid.New().String()
fastLinkService.NewSession(deviceNo, sessionId, sessionGuid, clientType, wsConn)
wsConn.WriteMessage(websocket.TextMessage, []byte("0{\"sid\":\""+guid.New().String()+"\",\"upgrades\":[\"websocket\"],\"pingInterval\":25000,\"pingTimeout\":60000}"))
wsConn.WriteMessage(websocket.TextMessage, []byte("40"))
if clientType == CLIENT_TYPE_FASTLINK_SERVICE {
Logger.Println("Online DeviceNo:" + deviceNo + " Session:" + sessionId)
fastLinkService.SetOnlineStatus(deviceNo)
device := fastLinkService.GetDeviceByNo(deviceNo)
if device != nil && device.BelongUser != "" {
notifyDeviceChange(device.BelongUser)
}
}
for {
wsConn.SetReadDeadline(time.Now().In(TimeLocation).Add(time.Second * 60))
messageType, p, readError := wsConn.ReadMessage()
if readError != nil {
Logger.Println("Service WebSocket异常断开," + wsConn.RemoteAddr().String() + ",异常信息:" + readError.Error())
fastLinkService.RemoveSession(sessionId, sessionGuid)
if clientType == CLIENT_TYPE_FASTLINK_SERVICE {
Logger.Println("Offline DeviceNo:" + deviceNo + " Session:" + sessionId)
fastLinkService.SetOnlineStatus(deviceNo)
device := fastLinkService.GetDeviceByNo(deviceNo)
if device != nil {
//推送通知
notifyDeviceChange(device.BelongUser)
}
}
wsConn.Close()
return
}
if messageType == websocket.CloseMessage {
Logger.Println("Service WebSocket断开," + wsConn.RemoteAddr().String())
fastLinkService.RemoveSession(sessionId, sessionGuid)
if clientType == CLIENT_TYPE_FASTLINK_SERVICE {
Logger.Println("Offline DeviceNo:" + deviceNo + " Session:" + sessionId)
fastLinkService.SetOnlineStatus(deviceNo)
device := fastLinkService.GetDeviceByNo(deviceNo)
if device != nil {
//推送通知
notifyDeviceChange(device.BelongUser)
}
}
wsConn.Close()
return
}
strData := string(p)
//fmt.Printf("DATA:" + strData + "\n")
index := strings.Index(strData, "[")
cmd := ""
var items []interface{}
if index != -1 {
cmd = strData[0:index]
json.Unmarshal([]byte(strData[index:]), &items)
} else {
cmd = strData
}
switch cmd {
case "2":
if tokenOfSession != "" {
fastLinkService.RenewToken(tokenOfSession)
}
wsConn.WriteMessage(websocket.TextMessage, []byte("3"))
case "42":
if items[0] == "KeepAlive" {
wsConn.WriteMessage(websocket.TextMessage, []byte("42[\"KeepAliveAck\",{\"code\":200,\"message\":\"\",\"success\":true,\"error\":false}]"))
} else if items[0] == "message" {
msg := items[1].(map[string]interface{})["message"].(string)
var messageInfo *MessageInfo
json.Unmarshal([]byte(msg), &messageInfo)
if messageInfo != nil {
switch messageInfo.Method {
case "AddDevice":
var param AddDeviceParam
param.DeviceName = messageInfo.Params.(map[string]interface{})["deviceName"].(string)
param.DeviceNo = messageInfo.Params.(map[string]interface{})["deviceNo"].(string)
device := fastLinkService.AddDevice(param.DeviceNo, param.DeviceName)
addDeviceResp := &MessageResponse{
Id: messageInfo.Id,
Method: "AddDeviceAck",
Result: &AddDeviceResponse{
Code: 200,
DeviceId: device.DeviceId,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, addDeviceResp))
case "CheckVersion":
checkVersionResp := &MessageResponse{
Id: messageInfo.Id,
Method: "CheckVersionAck",
Result: &CheckVersionResponse{
Code: 200,
DownloadUrl: "",
IsUpdate: false,
NewVersion: "1.4.2.0",
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, checkVersionResp))
case "GetDeviceRemoteControlInfo":
var param GetDeviceRemoteControlInfoParam
param.DeviceNo = messageInfo.Params.(map[string]interface{})["deviceNo"].(string)
param.DeviceId = int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
device := fastLinkService.GetDeviceByNo(param.DeviceNo)
if device != nil {
getDeviceRemoteControlInfoResp := &MessageResponse{
Id: messageInfo.Id,
Method: "GetDeviceRemoteControlInfoAck",
Result: &GetDeviceRemoteControlInfoResponse{
Code: 200,
DeviceId: device.DeviceId,
IdentificationCode: device.IdentificationCode,
ShareUrl: WEB_URL + "?d=" + base64.StdEncoding.EncodeToString([]byte(device.DeviceNo)) + "&r=" + device.ShareRand,
VerificationCode: device.VerificationCode,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, getDeviceRemoteControlInfoResp))
}
case "GetFileTransferConfig":
getFileTransferConfigResp := &MessageResponse{
Id: messageInfo.Id,
Method: "GetFileTransferConfigAck",
Result: &GetFileTransferConfigResponse{
Code: 200,
DownloadSpeedRatio: 80,
UploadSpeedRatio: 80,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo+"_service", getFileTransferConfigResp))
case "GetTurnTransferConfig":
getTurnTransferConfigResp := &MessageResponse{
Id: messageInfo.Id,
Method: "GetTurnTransferConfigAck",
Result: &GetTurnTransferConfigResponse{
Code: 200,
VideoBitrate: 4194377,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo+"_service", getTurnTransferConfigResp))
case "Login":
var param LoginParam
param.PhoneNo = messageInfo.Params.(map[string]interface{})["phoneNo"].(string)
param.Password = messageInfo.Params.(map[string]interface{})["password"].(string)
param.DeviceId = int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
token := fastLinkService.Login(param.PhoneNo, param.Password, param.DeviceId)
loginResp := &MessageResponse{
Id: messageInfo.Id,
Method: "LoginAck",
}
result := &LoginResponse{}
if token == "" {
result.Code = 1009
} else {
result.Code = 200
result.Token = token
notifyDeviceChange(param.PhoneNo)
}
loginResp.Result = result
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, loginResp))
tokenOfSession = token
fastLinkService.BindSessionToToken(sessionId, token)
case "Logout":
token := messageInfo.Params.(map[string]interface{})["token"].(string)
fastLinkService.RemoveToken(token)
logoutResp := &MessageResponse{
Id: messageInfo.Id,
Method: "LogoutAck",
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, logoutResp))
case "GetDevices":
token := messageInfo.Params.(map[string]interface{})["token"].(string)
deviceList := fastLinkService.GetDeviceByToken(token)
var dList []*DeviceResponse
for _, info := range deviceList {
d := &DeviceResponse{
DeviceId: info.DeviceId,
DeviceName: info.DeviceName,
DeviceNo: info.DeviceNo,
}
if info.CustomName != "" {
d.DeviceName = info.CustomName
}
if info.Online {
d.OnlineState = 1
} else {
d.OnlineState = 0
}
dList = append(dList, d)
}
getDevicesResp := &MessageResponse{
Id: messageInfo.Id,
Method: "GetDevicesAck",
Result: &GetDeviceResponse{
Code: 200,
Devices: dList,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, getDevicesResp))
case "UpdateDeviceVerificationCode":
paramDeviceNo := messageInfo.Params.(map[string]interface{})["deviceNo"].(string)
device := fastLinkService.RefreshDeviceVerificationCode(paramDeviceNo)
if device != nil {
updateDeviceVerificationCodeResp := &MessageResponse{
Id: messageInfo.Id,
Method: "UpdateDeviceVerificationCodeAck",
Result: &GetDeviceRemoteControlInfoResponse{
Code: 200,
DeviceId: device.DeviceId,
IdentificationCode: device.IdentificationCode,
ShareUrl: WEB_URL + "?d=" + device.DeviceNo + "&r=" + device.ShareRand,
VerificationCode: device.VerificationCode,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, updateDeviceVerificationCodeResp))
}
case "GetDeviceVerificationType":
paramDeviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
device := fastLinkService.GetDeviceById(paramDeviceId)
verificationType := 0
if device != nil {
verificationType = device.VerificationType
}
getDeviceVerificationTypeResp := &MessageResponse{
Id: messageInfo.Id,
Method: "GetDeviceVerificationTypeAck",
Result: &GetDeviceVerificationTypeResponse{
Code: 200,
VerificationType: verificationType,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, getDeviceVerificationTypeResp))
case "UpdateDeviceVerificationType":
verifyDeviceNo := messageInfo.Params.(map[string]interface{})["deviceNo"].(string)
verifyPass := messageInfo.Params.(map[string]interface{})["password"].(string)
verifyType := int(messageInfo.Params.(map[string]interface{})["verificationType"].(float64))
deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
device := fastLinkService.GetDeviceByNo(verifyDeviceNo)
if device != nil {
switch verifyType {
case 0:
device.VerificationType = 0
device.TwoStepPass = ""
case 1:
//未实现
device.VerificationType = 0
device.TwoStepPass = ""
case 2:
device.VerificationType = 2
device.TwoStepPass = verifyPass
}
}
updateDeviceVerificationTypeResp := &MessageResponse{
Id: messageInfo.Id,
Method: "UpdateDeviceVerificationTypeAck",
Result: &DeleteDeviceResponse{
Code: 200,
DeviceId: deviceId,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, updateDeviceVerificationTypeResp))
case "StartRemoteControl":
remoteControlParam := StartRemoteControlParam{
Type: int(messageInfo.Params.(map[string]interface{})["type"].(float64)),
Token: messageInfo.Params.(map[string]interface{})["token"].(string),
RemoteDeviceId: int(messageInfo.Params.(map[string]interface{})["remoteDeviceId"].(float64)),
RemoteIdentificationCode: messageInfo.Params.(map[string]interface{})["remoteIdentificationCode"].(string),
RemoteVerificationCode: messageInfo.Params.(map[string]interface{})["remoteVerificationCode"].(string),
VerificationType: int(messageInfo.Params.(map[string]interface{})["verificationType"].(float64)),
UserName: messageInfo.Params.(map[string]interface{})["userName"].(string),
Password: messageInfo.Params.(map[string]interface{})["password"].(string),
}
var device *DeviceInfo
if remoteControlParam.RemoteDeviceId != 0 {
device = fastLinkService.GetDeviceById(remoteControlParam.RemoteDeviceId)
} else {
device = fastLinkService.GetDeviceByIdentificationCode(remoteControlParam.RemoteIdentificationCode)
}
if device.Online && device.Visible {
verifyResult := true
userName := "游客"
if remoteControlParam.Token != "" {
userName = fastLinkService.GetUserByToken(remoteControlParam.Token)
if device.BelongUser != userName {
verifyResult = false
}
} else {
if device.VerificationCode != remoteControlParam.RemoteVerificationCode || device.IdentificationCode != remoteControlParam.RemoteIdentificationCode {
verifyResult = false
}
}
if device.VerificationType == 2 && device.TwoStepPass != "" {
if device.TwoStepPass != remoteControlParam.Password {
verifyResult = false
}
}
if !verifyResult {
errorResp := &MessageResponse{
Id: messageInfo.Id,
Method: "StartRemoteControlAck",
Result: &ErrorResponse{
Code: 5004,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, errorResp))
} else {
fastLinkService.RenewToken(remoteControlParam.Token)
clientId := GenShortGUID()
streamToken := GenShortGUID()
fastLinkService.PrepareSignalSession(clientId, device.DeviceId, device.DeviceNo, streamToken, userName)
targetRemoteControlResp := &RemoteStartRemoteControlResponse{
Id: guid.New().String(),
Method: "SetStreamingConfig",
Params: RemoteStreamingConfig{
ClientId: clientId,
SignalServer: globalConfig.SignalServer,
StunAddrs: globalConfig.StunServers,
Token: streamToken,
TurnAddrs: globalConfig.TurnServers,
},
}
remoteSession := fastLinkService.GetSession(device.DeviceNo, CLIENT_TYPE_FASTLINK_SERVICE)
remoteSession.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(device.DeviceNo+"_service", targetRemoteControlResp))
//推送UI提示
notifyOnlineUserChange(device.DeviceNo)
startRemoteControlResp := &MessageResponse{
Id: messageInfo.Id,
Method: "StartRemoteControlAck",
Result: &StartRemoteControlResponse{
Code: 200,
StreamingConfig: StreamingConfig{
ClientId: clientId,
ClientIds: []string{},
ServiceId: device.DeviceNo,
SignalServer: globalConfig.SignalServer,
StunAddrs: globalConfig.StunServers,
Token: streamToken,
TurnAddrs: globalConfig.TurnServers,
},
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, startRemoteControlResp))
}
} else {
errorResp := &MessageResponse{
Id: messageInfo.Id,
Method: "StartRemoteControlAck",
Result: &ErrorResponse{
Code: 5007,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, errorResp))
}
case "GetOnlineUsers":
paramDeviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
clients := fastLinkService.GetSignalSessionByDeviceId(paramDeviceId)
var onlineUsers []OnlineUser
onlineUsers = []OnlineUser{}
for _, client := range clients {
onlineUsers = append(onlineUsers, OnlineUser{
ClientId: client.Token,
ClientOS: "Windows 8(OS build number: 9200)",
UserName: client.StreamUser,
VisitTime: client.CreateTime.Format("2006-01-02 15:04"),
})
}
getOnlineUsersResp := &MessageResponse{
Id: messageInfo.Id,
Method: "GetOnlineUsersAck",
Result: &GetOnlineUsersResponse{
Code: 200,
DeviceId: paramDeviceId,
Users: onlineUsers,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, getOnlineUsersResp))
case "VerifyStreamingToken":
streamToken := messageInfo.Params.(map[string]interface{})["token"].(string)
clientId := messageInfo.Params.(map[string]interface{})["clientId"].(string)
signalSession := fastLinkService.GetSignalSession(clientId)
if streamToken == signalSession.StreamToken {
verifyStreamingTokenResp := &MessageResponse{
Id: messageInfo.Id,
Method: "VerifyStreamingTokenAck",
Result: &SimpleResponse{
Code: 200,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo+"_service", verifyStreamingTokenResp))
}
case "DeleteDevice":
token := messageInfo.Params.(map[string]interface{})["token"].(string)
deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
userName := fastLinkService.GetUserByToken(token)
device := fastLinkService.GetDeviceById(deviceId)
if device != nil && userName != "" && device.BelongUser == userName {
fastLinkService.RenewToken(token)
device.Visible = false
//推送通知
notifyDeviceChange(userName)
}
deleteDeviceResp := &MessageResponse{
Id: messageInfo.Id,
Method: "DeleteDeviceAck",
Result: &DeleteDeviceResponse{
Code: 200,
DeviceId: deviceId,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, deleteDeviceResp))
case "BindDevice":
token := messageInfo.Params.(map[string]interface{})["token"].(string)
bindDeviceNo := messageInfo.Params.(map[string]interface{})["deviceNo"].(string)
deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
userName := fastLinkService.GetUserByToken(token)
device := fastLinkService.GetDeviceByNo(bindDeviceNo)
if device != nil && userName != "" {
fastLinkService.RenewToken(token)
device.BelongUser = userName
device.Visible = true
//推送通知
notifyDeviceChange(userName)
}
deleteDeviceResp := &MessageResponse{
Id: messageInfo.Id,
Method: "BindDeviceAck",
Result: &DeleteDeviceResponse{
Code: 200,
DeviceId: deviceId,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, deleteDeviceResp))
case "UpdateDeviceVerificationUpdateFrequency":
//未实现,直接返回
deleteDeviceResp := &MessageResponse{
Id: messageInfo.Id,
Method: "UpdateDeviceVerificationUpdateFrequencyAck",
Result: &SimpleResponse{
Code: 200,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, deleteDeviceResp))
case "RebootDevice":
token := messageInfo.Params.(map[string]interface{})["token"].(string)
deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
device := fastLinkService.GetDeviceById(deviceId)
user := fastLinkService.GetUserByToken(token)
if device != nil && user != "" && device.BelongUser == user {
fastLinkService.RenewToken(token)
session := fastLinkService.GetSession(device.DeviceNo, CLIENT_TYPE_FASTLINK_SERVICE)
if session != nil {
notifyResp := &NotifyResponse{
Id: guid.New().String(),
Method: "NotifyReboot",
Params: EmptyObj{},
}
session.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(session.DeviceNo+"_service", notifyResp))
}
}
rebootDeviceResp := &MessageResponse{
Id: messageInfo.Id,
Method: "RebootDeviceAck",
Result: &AddDeviceResponse{
Code: 200,
DeviceId: deviceId,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, rebootDeviceResp))
case "ShutdownDevice":
token := messageInfo.Params.(map[string]interface{})["token"].(string)
deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
device := fastLinkService.GetDeviceById(deviceId)
user := fastLinkService.GetUserByToken(token)
if device != nil && user != "" && device.BelongUser == user {
fastLinkService.RenewToken(token)
session := fastLinkService.GetSession(device.DeviceNo, CLIENT_TYPE_FASTLINK_SERVICE)
if session != nil {
notifyResp := &NotifyResponse{
Id: guid.New().String(),
Method: "NotifyShutdown",
Params: EmptyObj{},
}
session.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(session.DeviceNo+"_service", notifyResp))
}
}
shutdownDeviceResp := &MessageResponse{
Id: messageInfo.Id,
Method: "ShutdownDeviceAck",
Result: &AddDeviceResponse{
Code: 200,
DeviceId: deviceId,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, shutdownDeviceResp))
case "UpdateDeviceName":
token := messageInfo.Params.(map[string]interface{})["token"].(string)
deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
newDeviceName := messageInfo.Params.(map[string]interface{})["newDeviceName"].(string)
user := fastLinkService.GetUserByToken(token)
device := fastLinkService.GetDeviceById(deviceId)
if user != "" && device != nil && device.BelongUser == user {
fastLinkService.RenewToken(token)
device.CustomName = newDeviceName
notifyDeviceChange(user)
}
updateDeviceNameResp := &MessageResponse{
Id: messageInfo.Id,
Method: "UpdateDeviceNameAck",
Result: &AddDeviceResponse{
Code: 200,
DeviceId: deviceId,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, updateDeviceNameResp))
case "ForceClientOffline":
deviceId := int(messageInfo.Params.(map[string]interface{})["deviceId"].(float64))
offlineDeviceNo := messageInfo.Params.(map[string]interface{})["deviceNo"].(string)
device := fastLinkService.GetDeviceByNo(offlineDeviceNo)
if device != nil && device.DeviceId == deviceId {
session := fastLinkService.GetSession(offlineDeviceNo, CLIENT_TYPE_FASTLINK_SERVICE)
if session != nil {
tClientIds := messageInfo.Params.(map[string]interface{})["clientIds"].([]interface{})
var clientIds []string
clientIds = []string{}
for _, id := range tClientIds {
clientIds = append(clientIds, id.(string))
}
notifyResp := &NotifyResponse{
Id: guid.New().String(),
Method: "NotifyClientOffline",
Params: ForceClientOfflineParam{
ClientIds: clientIds,
Reason: 3,
},
}
session.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(session.DeviceNo+"_service", notifyResp))
}
}
forceClientOfflineResp := &MessageResponse{
Id: messageInfo.Id,
Method: "ForceClientOfflineAck",
Result: &SimpleResponse{
Code: 200,
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, forceClientOfflineResp))
case "SetStreamingConfigAck":
default:
errorResp := &MessageErrorResponse{
Method: messageInfo.Method,
Error: &ErrorResponse{
Code: 2004,
Message: "请求调用的方法不存在",
},
}
wsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, errorResp))
}
}
}
}
}
}
func notifyDeviceChange(user string) {
userUISessions := fastLinkService.GetSessionsByUser(user, CLIENT_TYPE_FASTLINK_UI)
for _, session := range userUISessions {
notifyResp := &NotifyResponse{
Id: guid.New().String(),
Method: "NotifyDevicesChange",
Params: EmptyObj{},
}
Logger.Println("notifyDeviceChange: DeviceNo:" + session.DeviceNo + " User:" + user)
session.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(session.DeviceNo, notifyResp))
}
}
func notifyOnlineUserChange(deviceNo string) {
remoteUISession := fastLinkService.GetSession(deviceNo, CLIENT_TYPE_FASTLINK_UI)
if remoteUISession != nil {
notifyResp := &NotifyResponse{
Id: guid.New().String(),
Method: "NotifyOnlineUsersChange",
Params: EmptyObj{},
}
Logger.Println("notifyOnlineUserChange: DeviceNo:" + deviceNo)
remoteUISession.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(deviceNo, notifyResp))
}
}
func makeMessageResponse(deviceNo string, params interface{}) []byte {
var result []interface{}
result = append(result, "message")
var msg map[string]interface{}
msg = make(map[string]interface{})
msg["deviceNo"] = deviceNo
marshal, _ := json.Marshal(params)
msg["message"] = string(marshal)
result = append(result, msg)
bytes, _ := json.Marshal(result)
return append([]byte("42"), bytes...)
}
+117
View File
@@ -0,0 +1,117 @@
package main
import (
"encoding/json"
"fmt"
"github.com/beevik/guid"
"github.com/gorilla/websocket"
"net/http"
"strings"
"time"
)
func signalHandler(w http.ResponseWriter, r *http.Request) {
token := r.FormValue("token")
if token == "" {
fmt.Println("signalHandler Error : token is empty")
}
wsConn, upgradeErr := upgrader.Upgrade(w, r, w.Header())
if upgradeErr != nil {
return
}
defer func() {
if reco := recover(); reco != any(nil) {
fmt.Printf("Signal Runtime error caught: %v", reco)
}
}()
sessionGuid := guid.New().String()
fastLinkService.NewSignalSession(token, sessionGuid, wsConn)
wsConn.WriteMessage(websocket.TextMessage, []byte("0{\"sid\":\""+guid.New().String()+"\",\"upgrades\":[\"websocket\"],\"pingInterval\":25000,\"pingTimeout\":60000}"))
wsConn.WriteMessage(websocket.TextMessage, []byte("40"))
wsConn.WriteMessage(websocket.TextMessage, []byte("42[\"server-authenticated\",{\"uid\":\""+token+"\",\"authenticated\":true}]"))
for {
wsConn.SetReadDeadline(time.Now().In(TimeLocation).Add(time.Second * 60))
messageType, p, readError := wsConn.ReadMessage()
if readError != nil {
Logger.Println("Signal WebSocket异常断开," + wsConn.RemoteAddr().String() + ",异常信息:" + readError.Error())
signalSession := fastLinkService.GetSignalSession(token)
fastLinkService.RemoveSignalSession(token, sessionGuid)
if signalSession != nil {
//推送UI提示
notifyOnlineUserChange(signalSession.RelateDeviceNo)
}
wsConn.Close()
return
}
if messageType == websocket.CloseMessage {
Logger.Println("Signal WebSocket断开," + wsConn.RemoteAddr().String())
signalSession := fastLinkService.GetSignalSession(token)
fastLinkService.RemoveSignalSession(token, sessionGuid)
if signalSession != nil {
//推送UI提示
notifyOnlineUserChange(signalSession.RelateDeviceNo)
}
wsConn.Close()
return
}
strData := string(p)
//fmt.Printf("SIGNAL:" + strData + "\n")
index := strings.Index(strData, "[")
cmd := ""
var items []interface{}
if index != -1 {
cmd = strData[0:index]
json.Unmarshal([]byte(strData[index:]), &items)
} else {
cmd = strData
}
if len(cmd) > 1 && cmd[:2] == "42" {
cmd = "42"
}
switch cmd {
case "2":
wsConn.WriteMessage(websocket.TextMessage, []byte("3"))
case "42":
if items[0] == "KeepAlive" {
wsConn.WriteMessage(websocket.TextMessage, []byte("42[\"KeepAliveAck\",{}]"))
} else if items[0] == "owt-message" {
from := ""
if _, ok := items[1].(map[string]interface{})["from"]; ok {
from = items[1].(map[string]interface{})["from"].(string)
}
if from == "" {
from = token
}
to := items[1].(map[string]interface{})["to"].(string)
data := items[1].(map[string]interface{})["data"].(string)
target := fastLinkService.GetSignalSession(to)
if target != nil {
target.WsConn.WriteMessage(websocket.TextMessage, makeOwtMessage(from, to, data))
}
}
}
}
}
func makeOwtMessage(from string, to string, data string) []byte {
var message []interface{}
message = append(message, "owt-message")
var m map[string]string
m = make(map[string]string)
m["from"] = from
m["to"] = to
m["data"] = data
message = append(message, m)
marshal, _ := json.Marshal(message)
return append([]byte("42"), marshal...)
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

+24
View File
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="keywords" content="fastLink,FASTLINK,顺网云游戏,云游戏,顺网云玩,顺网">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,minimal-ui">
<meta http-equiv="X-UA-Compatible" content="ie=edge,chrome=1">
<meta name="msapplication-tap-highlight" content="no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="browsermode" content="application">
<meta name="full-screen" content="yes">
<meta name="x5-fullscreen" content="true">
<meta name="x5-page-mode" content="app">
<meta name="360-fullscreen" content="true">
<meta name="wap-font-scale" content="no">
<meta name="format-detection" content="telphone=no, email=no">
<title>FASTLINK</title>
<link rel="shortcut icon" href="favicon.png"><link href="static1/css/tool.e82ab3594a815ab433dc.css" rel="stylesheet"></head>
<body>
<div id="video-and-stats"></div>
<script src="./static1/js/hammer.js"></script>
<script src="static1/js/runtimechunk~tool.js"></script><script src="static1/js/2.7473f57.js"></script><script src="static1/js/1.bdd544c.js"></script></body>
</html>
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+458
View File
@@ -0,0 +1,458 @@
package main
import (
"encoding/base64"
"encoding/json"
"github.com/beevik/guid"
"github.com/gorilla/websocket"
"io/ioutil"
"net/http"
"strings"
)
type WebApiRequest struct {
DeviceNo string `json:"deviceNo"`
Random string `json:"random"`
ClientNo string `json:"clientNo"`
UserName string `json:"userName"`
VerificationPassword string `json:"verificationPassword"`
}
type WebApiResponse struct {
TraceId interface{} `json:"traceId"`
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
Success bool `json:"success"`
Error bool `json:"error"`
}
type WebCheckData struct {
Pass bool `json:"pass"`
}
type DeviceVerificationTypeData struct {
DeviceId interface{} `json:"deviceId"`
VerificationType interface{} `json:"verificationType"`
}
type IdTransferData struct {
StreamingConfig StreamingConfig `json:"streamingConfig"`
StreamRecordId int `json:"streamRecordId"` //记录分析,没啥用,未实现相关功能
}
type LoginRequest struct {
Password string `json:"password"`
Phone string `json:"phone"`
}
type AppDeviceListData struct {
DeviceId int `json:"deviceId"`
DeviceNo string `json:"deviceNo"`
DeviceName string `json:"deviceName"`
ExpireTime interface{} `json:"expireTime"`
ExpireTimeStr interface{} `json:"expireTimeStr"`
OnlineState int `json:"onlineState"`
EnableConnect int `json:"enableConnect"`
ClientVersion interface{} `json:"clientVersion"`
}
type RegisterModel struct {
Code string `json:"code"`
Password string `json:"password"`
Password2 string `json:"password2"`
Phone string `json:"phone"`
UserName string `json:"userName"`
}
func checkHandler(w http.ResponseWriter, r *http.Request) {
data, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()
var model *WebApiRequest
json.Unmarshal(data, &model)
decodeString, _ := base64.StdEncoding.DecodeString(model.DeviceNo)
model.DeviceNo = string(decodeString)
result := fastLinkService.CheckWebLogin(model.DeviceNo, model.Random)
resp := WebApiResponse{
TraceId: nil,
Code: 200,
Message: "",
Data: &WebCheckData{
Pass: true,
},
Success: true,
Error: false,
}
switch result {
case 1:
resp.Data = nil
resp.Error = true
resp.Success = false
resp.Message = "远程主机没有分享"
resp.Code = 500
case 2:
resp.Data = nil
resp.Error = true
resp.Success = false
resp.Message = "要连接的主机不存在"
resp.Code = 500
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
}
func deviceVerificationTypeHandler(w http.ResponseWriter, r *http.Request) {
data, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()
var model *WebApiRequest
json.Unmarshal(data, &model)
device := fastLinkService.GetDeviceByNo(model.DeviceNo)
vData := &DeviceVerificationTypeData{
DeviceId: nil,
VerificationType: nil,
}
resp := WebApiResponse{
TraceId: nil,
Code: 200,
Message: "",
Data: vData,
Success: true,
Error: false,
}
if device != nil {
vData.DeviceId = device.DeviceId
vData.VerificationType = device.VerificationType
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
}
func idTransferHandler(w http.ResponseWriter, r *http.Request) {
data, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()
var model *WebApiRequest
json.Unmarshal(data, &model)
device := fastLinkService.GetDeviceByNo(model.DeviceNo)
if device == nil {
resp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "设备不存在",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
} else {
if device.Online && device.Visible {
if device.VerificationType == 2 && device.TwoStepPass != "" && device.TwoStepPass != model.VerificationPassword {
resp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "访问密码不正确",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
return
}
streamToken := GenShortGUID()
if model.UserName == "" {
model.UserName = "WEB客户端"
}
fastLinkService.PrepareSignalSession(model.ClientNo, device.DeviceId, device.DeviceNo, streamToken, model.UserName)
targetRemoteControlResp := &RemoteStartRemoteControlResponse{
Id: guid.New().String(),
Method: "SetStreamingConfig",
Params: RemoteStreamingConfig{
ClientId: model.ClientNo,
SignalServer: globalConfig.SignalServer,
StunAddrs: globalConfig.StunServers,
Token: streamToken,
TurnAddrs: globalConfig.TurnServers,
},
}
remoteSession := fastLinkService.GetSession(device.DeviceNo, CLIENT_TYPE_FASTLINK_SERVICE)
remoteSession.WsConn.WriteMessage(websocket.TextMessage, makeMessageResponse(device.DeviceNo+"_service", targetRemoteControlResp))
//推送UI提示
notifyOnlineUserChange(device.DeviceNo)
idTransferData := IdTransferData{
StreamingConfig: StreamingConfig{
ClientId: model.ClientNo,
ClientIds: []string{model.ClientNo},
ServiceId: model.DeviceNo,
SignalServer: globalConfig.SignalServer,
StunAddrs: globalConfig.StunServers,
Token: streamToken,
TurnAddrs: globalConfig.TurnServers,
},
StreamRecordId: 0,
}
resp := WebApiResponse{
TraceId: nil,
Code: 200,
Message: "",
Data: idTransferData,
Success: true,
Error: false,
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
} else {
resp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "远程主机不在线",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
}
}
}
func closeHandler(w http.ResponseWriter, r *http.Request) {
//记录埋点用,未实现,直接返回
resp := WebApiResponse{
TraceId: nil,
Code: 200,
Message: "",
Data: nil,
Success: true,
Error: false,
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
}
func loginForAppHandler(w http.ResponseWriter, r *http.Request) {
data, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()
var model *LoginRequest
json.Unmarshal(data, &model)
success := fastLinkService.CheckUser(model.Phone, model.Password)
resp := WebApiResponse{
TraceId: nil,
Code: 200,
Message: "",
Data: nil,
Success: true,
Error: false,
}
if !success {
resp.Success = false
resp.Error = true
resp.Code = 500
resp.Message = "用户名或密码不正确!"
}
token := fastLinkService.NewToken(model.Phone, TOKEN_TYPE_APP)
http.SetCookie(w, &http.Cookie{
Name: "token",
Value: token,
})
marshal, _ := json.Marshal(resp)
w.Write(marshal)
}
func appListDeviceHandler(w http.ResponseWriter, r *http.Request) {
cookie := r.Header.Get("Cookie")
user := ""
token := ""
if len(cookie) > 7 {
index := strings.Index(cookie, "token=")
token = cookie[index+6:]
user = fastLinkService.GetUserByToken(token)
}
if user == "" {
errResp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "用户未登录",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(errResp)
w.Write(marshal)
return
}
fastLinkService.RenewToken(token)
devices := fastLinkService.GetDeviceByToken(token)
var data []*AppDeviceListData
for _, device := range devices {
t := &AppDeviceListData{
DeviceId: device.DeviceId,
DeviceNo: device.DeviceNo,
DeviceName: device.DeviceName,
ExpireTime: nil,
ExpireTimeStr: nil,
ClientVersion: nil,
}
if device.CustomName != "" {
t.DeviceName = device.CustomName
}
if device.Online {
t.OnlineState = 1
} else {
t.OnlineState = 0
}
if device.Visible {
t.EnableConnect = 1
} else {
t.EnableConnect = 0
}
data = append(data, t)
}
resp := WebApiResponse{
TraceId: nil,
Code: 200,
Message: "",
Data: data,
Success: true,
Error: false,
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
}
func logoutHandler(w http.ResponseWriter, r *http.Request) {
cookie := r.Header.Get("Cookie")
user := ""
token := ""
if len(cookie) > 7 {
index := strings.Index(cookie, "token=")
token = cookie[index+6:]
user = fastLinkService.GetUserByToken(token)
}
if user == "" {
errResp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "用户未登录",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(errResp)
w.Write(marshal)
return
}
fastLinkService.RemoveToken(token)
resp := WebApiResponse{
TraceId: nil,
Code: 200,
Message: "",
Data: nil,
Success: true,
Error: false,
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
}
func registerHandler(w http.ResponseWriter, r *http.Request) {
data, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()
var model *RegisterModel
json.Unmarshal(data, &model)
if model.UserName == "" || model.Phone == "" {
errResp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "用户名不能为空",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(errResp)
w.Write(marshal)
return
}
if model.Password == "" {
errResp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "密码不能为空",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(errResp)
w.Write(marshal)
return
}
if model.Password != model.Password2 {
errResp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "两次密码输入不一致",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(errResp)
w.Write(marshal)
return
}
if model.Password != model.Password2 {
errResp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "两次密码输入不一致",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(errResp)
w.Write(marshal)
return
}
exist := fastLinkService.CheckUserExist(model.UserName)
if exist {
errResp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "此手机号已被其他用户绑定!",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(errResp)
w.Write(marshal)
return
}
fastLinkService.AddUser(model.UserName, model.Password)
resp := WebApiResponse{
TraceId: nil,
Code: 200,
Message: "",
Data: nil,
Success: true,
Error: false,
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
}
func sendCodeHandler(w http.ResponseWriter, r *http.Request) {
resp := WebApiResponse{
TraceId: nil,
Code: 500,
Message: "私服未实现发送验证码,输入任意验证码即可",
Data: nil,
Success: false,
Error: true,
}
marshal, _ := json.Marshal(resp)
w.Write(marshal)
}