Add some acquaintance network interface

This commit is contained in:
link 2022-03-11 18:01:09 +08:00
parent 9213f9e379
commit 892cd99eb3
13 changed files with 431 additions and 80 deletions

View file

@ -25,6 +25,7 @@ PWD = zimaboard
Email = user@gmail.com Email = user@gmail.com
Description = description Description = description
Initialized = false Initialized = false
Avatar =
[zerotier] [zerotier]
UserName = user UserName = user

View file

@ -33,7 +33,8 @@ func init() {
service.MyService = service.NewService(sqliteDB, loger2.NewOLoger()) service.MyService = service.NewService(sqliteDB, loger2.NewOLoger())
service.Cache = cache.Init() service.Cache = cache.Init()
//go service.UDPConnect([]string{}) //go service.UDPConnect([]string{})
//go service.SocketConnect() go service.SocketConnect()
//go service.UDPService()
route.InitFunction() route.InitFunction()
} }

View file

@ -16,6 +16,7 @@ type UserModel struct {
Email string Email string
Description string Description string
Initialized bool Initialized bool
Avatar string
} }
//服务配置 //服务配置

View file

@ -31,7 +31,7 @@ func GetDb(projectPath string) *gorm.DB {
return nil return nil
} }
gdb = db gdb = db
err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.PersionDownloadDBModel{}) err = db.AutoMigrate(&model2.TaskDBModel{}, &model2.AppNotify{}, &model2.AppListDBModel{}, &model2.SerialDisk{}, model2.PersionDownloadDBModel{}, model2.FriendModel{})
if err != nil { if err != nil {
fmt.Println("检查和创建数据库出错", err) fmt.Println("检查和创建数据库出错", err)
} }

View file

@ -291,11 +291,11 @@ func InitRouter() *gin.Engine {
v1PersonGroup.Use() v1PersonGroup.Use()
{ {
// v1PersonGroup.GET("/test", v1.PersonTest) // v1PersonGroup.GET("/test", v1.PersonTest)
// v1PersonGroup.GET("/users", v1.Users) //用户列表 v1PersonGroup.GET("/users", v1.GetPersionFriend) //用户列表
// v1PersonGroup.POST("/user", v1.Users) //添加用户 v1PersonGroup.POST("/user", v1.PostAddPersionFriend) //添加用户
// v1PersonGroup.GET("/directory", v1.Users) //文件列表 v1PersonGroup.GET("/directory", v1.GetPersionDirectory) //文件列表
v1PersonGroup.GET("/download", v1.GetPersionFile) //下载文件 //v1PersonGroup.GET("/download", v1.GetPersionFile) //下载文件
// v1PersonGroup.PUT("/edit/:id", v1.EditUser) //修改好友 v1PersonGroup.PUT("/edit/:token", v1.PutPersionNick) //修改好友
v1PersonGroup.GET("/list", v1.GetPersionDownloadList) //下载列表(需要考虑试试下载速度) v1PersonGroup.GET("/list", v1.GetPersionDownloadList) //下载列表(需要考虑试试下载速度)
// v1PersonGroup.PUT("/state/:id", v1.PutPersionCancelDownload) //修改下载状态(开始暂停删除) // v1PersonGroup.PUT("/state/:id", v1.PutPersionCancelDownload) //修改下载状态(开始暂停删除)

View file

@ -2,6 +2,7 @@ package v1
import ( import (
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"time" "time"
@ -83,3 +84,97 @@ func GetPersionDownloadList(c *gin.Context) {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)}) c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
} }
// @Summary add friend
// @Produce application/json
// @Accept application/json
// @Tags persion
// @Param token formData int true "Opponent token"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /persion/edit [put]
func PutPersionNick(c *gin.Context) {
token := c.Param("token")
nick := c.PostForm("nick")
if len(token) == 0 || len(nick) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
friend := model2.FriendModel{}
friend.Token = token
friend.NickName = nick
service.MyService.Friend().EditFriendNick(friend)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
// @Summary add friend
// @Produce application/json
// @Accept application/json
// @Tags persion
// @Param token formData int true "Opponent token"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /persion/users [get]
func GetPersionFriend(c *gin.Context) {
list := service.MyService.Friend().GetFriendList()
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: list})
}
// @Summary add friend
// @Produce application/json
// @Accept application/json
// @Tags persion
// @Param token formData int true "Opponent token"
// @Security ApiKeyAuth
// @Success 200 {string} string "ok"
// @Router /persion/user [post]
func PostAddPersionFriend(c *gin.Context) {
token := c.PostForm("token")
if len(token) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
//step:远程验证token是否存在
msg := model.MessageModel{}
msg.Type = types.PERSONADDFRIEND
msg.To = token
msg.Data = token
msg.From = config.ServerInfo.Token
msg.UUId = uuid.NewV4().String()
b, _ := json.Marshal(msg)
err := service.WebSocketConn.WriteMessage(websocket.TextMessage, b)
fmt.Println(err)
friend := model2.FriendModel{}
friend.Token = token
service.MyService.Friend().AddFriend(friend)
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS)})
}
func GetPersionDirectory(c *gin.Context) {
path := c.Query("path")
persion := c.Query("persion")
if len(path) == 0 && len(persion) == 0 {
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
return
}
//任务标识
uuid := uuid.NewV4().String()
m := model.MessageModel{}
m.Data = path
m.From = config.ServerInfo.Token
m.To = persion
m.Type = "directory"
m.UUId = uuid
result, err := service.Dial("192.168.2.225:9902", m)
if err != nil {
fmt.Println(err)
}
dataModel := []model.Path{}
if m.UUId == m.UUId {
dataModelByte, _ := json.Marshal(result.Data)
err := json.Unmarshal(dataModelByte, &dataModel)
fmt.Println(err)
}
c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: dataModel})
}

47
service/friend.go Normal file
View file

@ -0,0 +1,47 @@
package service
import (
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"gorm.io/gorm"
)
type FriendService interface {
AddFriend(m model2.FriendModel)
DeleteFriend(m model2.FriendModel)
EditFriendNick(m model2.FriendModel)
GetFriendById(m model2.FriendModel) model2.FriendModel
GetFriendList() (list []model2.FriendModel)
UpdateAddFriendType(m model2.FriendModel)
}
type friendService struct {
db *gorm.DB
}
func (p *friendService) AddFriend(m model2.FriendModel) {
p.db.Create(&m)
}
func (p *friendService) DeleteFriend(m model2.FriendModel) {
p.db.Where("token = ?", m.Token).Delete(&m)
}
func (p *friendService) EditFriendNick(m model2.FriendModel) {
p.db.Model(&m).Where("token = ?", m.Token).Update("nick_name", m.NickName)
}
func (p *friendService) GetFriendById(m model2.FriendModel) model2.FriendModel {
p.db.Model(m).Where("token = ?", m.Token).First(&m)
return m
}
func (p *friendService) GetFriendList() (list []model2.FriendModel) {
p.db.Select("nick_name", "avatar", "name", "profile", "token", "state").Find(&list)
return list
}
func (p *friendService) UpdateAddFriendType(m model2.FriendModel) {
p.db.Model(&m).Updates(m)
}
func NewFriendService(db *gorm.DB) FriendService {
return &friendService{db: db}
}

16
service/model/o_friend.go Normal file
View file

@ -0,0 +1,16 @@
package model
type FriendModel struct {
State int `json:"state"` //备用
CreatedAt string `gorm:"<-:create;autoCreateTime" json:"created_at"`
UpdatedAt string `gorm:"<-:create;<-:update;autoUpdateTime" json:"updated_at"`
NickName string `json:"nick_name"` //custom name
Avatar string `json:"avatar"` //头像
Name string `json:"name"`
Token string `gorm:"column:token;primary_key" json:"token"`
Profile string `json:"profile"`
}
func (p *FriendModel) TableName() string {
return "o_friend"
}

View file

@ -1,6 +1,7 @@
package service package service
import ( import (
"bufio"
"context" "context"
"crypto/cipher" "crypto/cipher"
"crypto/rand" "crypto/rand"
@ -17,6 +18,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"strconv"
"time" "time"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
@ -268,16 +270,10 @@ func generateTLSConfig() *tls.Config {
if err != nil { if err != nil {
panic(err) panic(err)
} }
// return &tls.Config{
// ClientSessionCache: globalSessionCache,
// RootCAs: root,
// InsecureSkipVerify: false,
// NextProtos: nil,
// SessionTicketsDisabled: true,
// }
return &tls.Config{ return &tls.Config{
Certificates: []tls.Certificate{tlsCert}, Certificates: []tls.Certificate{tlsCert},
NextProtos: []string{"quic-echo-example"}, NextProtos: []string{"bench"},
SessionTicketsDisabled: true,
} }
} }
@ -510,3 +506,197 @@ func AsyncUDPConnect(dst *net.UDPAddr) {
func NewPersonService(db *gorm.DB) PersonService { func NewPersonService(db *gorm.DB) PersonService {
return &personService{db: db} return &personService{db: db}
} }
//=======================================================================================================================================================================
var StreamList map[string]quic.Stream
var ServiceMessage chan model.MessageModel
func UDPService() {
quicConfig := &quic.Config{
ConnectionIDLength: 4,
KeepAlive: true,
}
srcAddr := &net.UDPAddr{
IP: net.IPv4zero, Port: 9902} //注意端口必须固定
fmt.Println(srcAddr.String())
listener, err := quic.ListenAddr(srcAddr.String(), generateTLSConfig(), quicConfig)
if err != nil {
fmt.Println(err)
}
defer listener.Close()
ctx := context.Background()
acceptFailures := 0
const maxAcceptFailures = 10
if err != nil {
panic(err)
}
for {
select {
case <-ctx.Done():
fmt.Println(ctx.Err())
return
default:
}
session, err := listener.Accept(ctx)
if err != nil {
fmt.Println("Listen (BEP/quic): Accepting connection:", err)
acceptFailures++
if acceptFailures > maxAcceptFailures {
// Return to restart the listener, because something
// seems permanently damaged.
fmt.Println(err)
return
}
// Slightly increased delay for each failure.
time.Sleep(time.Duration(acceptFailures) * time.Second)
continue
}
acceptFailures = 0
streamCtx, cancel := context.WithTimeout(ctx, time.Second*10)
stream, err := session.AcceptStream(streamCtx)
cancel()
if err != nil {
fmt.Println("failed to accept stream from %s: %v", session.RemoteAddr(), err)
_ = session.CloseWithError(1, err.Error())
continue
}
// prefixByte := make([]byte, 4)
// c1, err := io.ReadFull(stream, prefixByte)
// fmt.Println(c1, err)
// prefixLength, err := strconv.Atoi(string(prefixByte))
// if err != nil {
// fmt.Println(err)
// }
// messageByte := make([]byte, prefixLength)
// t, err := io.ReadFull(stream, messageByte)
// fmt.Println(t, err)
// m := model.MessageModel{}
// err = json.Unmarshal(messageByte, &m)
// if err != nil {
// fmt.Println(err)
// }
go ProcessingContent(stream)
}
}
//处理内容
func ProcessingContent(stream quic.Stream) {
//需要处理关闭问题
for {
prefixByte := make([]byte, 4)
c1, err := io.ReadFull(stream, prefixByte)
fmt.Println(c1)
if err != nil {
return
}
prefixLength, err := strconv.Atoi(string(prefixByte))
if err != nil {
fmt.Println(err)
}
messageByte := make([]byte, prefixLength)
t, err := io.ReadFull(stream, messageByte)
if err != nil {
return
}
fmt.Println(t, err)
m := model.MessageModel{}
err = json.Unmarshal(messageByte, &m)
fmt.Println(m)
if err != nil {
fmt.Println(err)
}
if m.Type == "hello" {
//什么也不做
continue
} else if m.Type == "directory" {
list := MyService.ZiMa().GetDirPath(m.Data.(string))
m.To = m.From
m.Data = list
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} else if m.Type == "file_data" {
SendFileData(stream, m.Data.(string), m.From, m.UUId)
break
} else if m.Type == types.PERSONADDFRIEND {
friend := model2.FriendModel{}
dataModelByte, _ := json.Marshal(m.Data)
err := json.Unmarshal(dataModelByte, &friend)
if err != nil {
fmt.Println(err)
continue
}
go MyService.Friend().UpdateAddFriendType(friend)
mi := model2.FriendModel{}
mi.Avatar = config.UserInfo.Avatar
mi.Profile = config.UserInfo.Description
mi.Name = config.UserInfo.UserName
m.To = m.From
m.Data = mi
m.Type = types.PERSONADDFRIEND
m.From = config.ServerInfo.Token
SendData(stream, m)
break
} else {
//不应有不做返回的数据
//ServiceMessage <- m
break
}
}
stream.Close()
}
//文件分片发送
func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
fStat, err := os.Stat(filePath)
if err != nil {
return err
}
blockSize, length := file.GetBlockInfo(fStat.Size())
f, err := os.Open(filePath)
if err != nil {
fmt.Println("读取失败", err)
return err
}
bufferedReader := bufio.NewReader(f)
buf := make([]byte, blockSize)
for i := 0; i < length; i++ {
tran := model.TranFileModel{}
_, err = bufferedReader.Read(buf)
if err == io.EOF {
fmt.Println("读取完毕", err)
}
tran.Hash = file.GetHashByContent(buf)
tran.Index = i
msg := model.MessageModel{}
msg.Type = "file_data"
msg.Data = tran
msg.From = config.ServerInfo.Token
msg.To = to
msg.UUId = uuid
b, _ := json.Marshal(msg)
stream.Write(b)
}
defer stream.Close()
return nil
}

View file

@ -33,6 +33,7 @@ type Repository interface {
Shortcuts() ShortcutsService Shortcuts() ShortcutsService
Search() SearchService Search() SearchService
Person() PersonService Person() PersonService
Friend() FriendService
} }
func NewService(db *gorm.DB, log loger2.OLog) Repository { func NewService(db *gorm.DB, log loger2.OLog) Repository {
@ -55,6 +56,7 @@ func NewService(db *gorm.DB, log loger2.OLog) Repository {
shortcuts: NewShortcutsService(db), shortcuts: NewShortcutsService(db),
search: NewSearchService(), search: NewSearchService(),
person: NewPersonService(db), person: NewPersonService(db),
friend: NewFriendService(db),
} }
} }
@ -76,8 +78,12 @@ type store struct {
shortcuts ShortcutsService shortcuts ShortcutsService
search SearchService search SearchService
person PersonService person PersonService
friend FriendService
} }
func (c *store) Friend() FriendService {
return c.friend
}
func (c *store) Rely() RelyService { func (c *store) Rely() RelyService {
return c.rely return c.rely
} }

View file

@ -4,12 +4,16 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"reflect"
"strings" "strings"
"time" "time"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/IceWhaleTech/CasaOS/types"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
uuid "github.com/satori/go.uuid"
) )
var WebSocketConn *websocket.Conn var WebSocketConn *websocket.Conn
@ -36,6 +40,32 @@ func SocketConnect() {
fmt.Println(err) fmt.Println(err)
//开始尝试udp链接 //开始尝试udp链接
go UDPConnect(content.Ips) go UDPConnect(content.Ips)
} else if msa.Type == types.PERSONADDFRIEND {
// new add friend
uuid := uuid.NewV4().String()
mi := model2.FriendModel{}
mi.Avatar = config.UserInfo.Avatar
mi.Profile = config.UserInfo.Description
mi.Name = config.UserInfo.UserName
m := model.MessageModel{}
m.Data = mi
m.From = config.ServerInfo.Token
m.To = msa.From
m.Type = types.PERSONADDFRIEND
m.UUId = uuid
result, err := Dial("192.168.2.225:9902", m)
friend := model2.FriendModel{}
if err != nil && !reflect.DeepEqual(result, friend) {
dataModelByte, _ := json.Marshal(result.Data)
err := json.Unmarshal(dataModelByte, &friend)
if err != nil {
fmt.Println(err)
}
}
if len(friend.Token) == 0 {
friend.Token = m.From
}
MyService.Friend().AddFriend(friend)
} }
} }
}() }()

View file

@ -1,7 +1,6 @@
package service package service
import ( import (
"bufio"
"context" "context"
"crypto/md5" "crypto/md5"
"crypto/tls" "crypto/tls"
@ -11,8 +10,8 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net" "net"
"os"
"strconv" "strconv"
"time"
"github.com/IceWhaleTech/CasaOS/model" "github.com/IceWhaleTech/CasaOS/model"
"github.com/IceWhaleTech/CasaOS/pkg/config" "github.com/IceWhaleTech/CasaOS/pkg/config"
@ -25,7 +24,9 @@ var UDPconn *net.UDPConn
var PeopleMap map[string]quic.Stream var PeopleMap map[string]quic.Stream
var Message chan model.MessageModel var Message chan model.MessageModel
func Dial(addr string, token string) error { func Dial(addr string, msg model.MessageModel) (m model.MessageModel, err error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
Message = make(chan model.MessageModel) Message = make(chan model.MessageModel)
quicConfig := &quic.Config{ quicConfig := &quic.Config{
ConnectionIDLength: 4, ConnectionIDLength: 4,
@ -36,21 +37,26 @@ func Dial(addr string, token string) error {
NextProtos: []string{"bench"}, NextProtos: []string{"bench"},
SessionTicketsDisabled: true, SessionTicketsDisabled: true,
} }
session, err := quic.DialAddr(addr, tlsConf, quicConfig)
defer session.CloseWithError(0, "") session, err := quic.DialAddrContext(ctx, addr, tlsConf, quicConfig)
if err != nil { if err != nil {
return err return m, err
} }
stream, err := session.OpenStreamSync(context.Background())
stream, err := session.OpenStreamSync(ctx)
if err != nil { if err != nil {
return err session.CloseWithError(1, err.Error())
return m, err
} }
SayHello(stream, token)
//写 SayHello(stream, msg.To)
SendData(stream, msg)
go ReadContent(stream) go ReadContent(stream)
//读 result := <-Message
//结果 stream.Close()
return nil return result, nil
} }
func SayHello(stream quic.Stream, to string) { func SayHello(stream quic.Stream, to string) {
@ -60,62 +66,17 @@ func SayHello(stream quic.Stream, to string) {
msg.To = to msg.To = to
msg.From = config.ServerInfo.Token msg.From = config.ServerInfo.Token
msg.UUId = uuid.NewV4().String() msg.UUId = uuid.NewV4().String()
b, _ := json.Marshal(msg) SendData(stream, msg)
prefixLength := file.PrefixLength(len(b))
data := append(prefixLength, b...)
stream.Write(data)
} }
var pathsss string var pathsss string
//文件分片发送
func SendFileData(stream quic.Stream, filePath, to, uuid string) error {
fStat, err := os.Stat(filePath)
if err != nil {
return err
}
blockSize, length := file.GetBlockInfo(fStat.Size())
f, err := os.Open(filePath)
if err != nil {
fmt.Println("读取失败", err)
return err
}
bufferedReader := bufio.NewReader(f)
buf := make([]byte, blockSize)
for i := 0; i < length; i++ {
tran := model.TranFileModel{}
_, err = bufferedReader.Read(buf)
if err == io.EOF {
fmt.Println("读取完毕", err)
}
tran.Hash = file.GetHashByContent(buf)
tran.Index = i
msg := model.MessageModel{}
msg.Type = "file_data"
msg.Data = tran
msg.From = config.ServerInfo.Token
msg.To = to
msg.UUId = uuid
b, _ := json.Marshal(msg)
stream.Write(b)
}
defer stream.Close()
return nil
}
//发送数据 //发送数据
func SendData(stream quic.Stream, m model.MessageModel) { func SendData(stream quic.Stream, m model.MessageModel) {
b, _ := json.Marshal(m) b, _ := json.Marshal(m)
stream.Write(b) prefixLength := file.PrefixLength(len(b))
data := append(prefixLength, b...)
stream.Write(data)
} }
//读取数据 //读取数据
@ -124,12 +85,12 @@ func ReadContent(stream quic.Stream) {
for { for {
prefixByte := make([]byte, 4) prefixByte := make([]byte, 4)
c1, err := io.ReadFull(stream, prefixByte) c1, err := io.ReadFull(stream, prefixByte)
fmt.Println(c1, err) fmt.Println(c1, err, string(prefixByte))
prefixLength, err := strconv.Atoi(string(prefixByte)) prefixLength, err := strconv.Atoi(string(prefixByte))
messageByte := make([]byte, prefixLength) messageByte := make([]byte, prefixLength)
t, err := io.ReadFull(stream, messageByte) t, err := io.ReadFull(stream, messageByte)
fmt.Println(t, err) fmt.Println(t, err, string(messageByte))
m := model.MessageModel{} m := model.MessageModel{}
err = json.Unmarshal(messageByte, &m) err = json.Unmarshal(messageByte, &m)
if err != nil { if err != nil {

3
types/persion.go Normal file
View file

@ -0,0 +1,3 @@
package types
const PERSONADDFRIEND = "add_user"