Commit 41ba857b by a2231243

format code

parent 698696c8
Pipeline #15511 failed with stages
in 13 seconds
# Default ignored files
/workspace.xml
\ No newline at end of file
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>
\ No newline at end of file
......@@ -2,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ppt_server.iml" filepath="$PROJECT_DIR$/.idea/ppt_server.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/ppt.iml" filepath="$PROJECT_DIR$/.idea/ppt.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
package api
import (
"ppt_server/app/model"
"ppt_server/app/service"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
var File = fileApi{}
type fileApi struct {
}
func (f *fileApi) Index(r *ghttp.Request) {
_ = r.Response.WriteJson(g.Map{
"code": 0,
"msg": "成功",
})
}
func (f *fileApi) Upload(r *ghttp.Request) {
var req model.FileUploadRequest
if err := r.Parse(&req); err != nil {
panic(err)
}
go service.File.Upload(&req)
_ = r.Response.WriteJson(g.Map{
"code": 0,
"msg": "成功",
})
}
func (f *fileApi) Callback(r *ghttp.Request) {
}
package internal
import (
"github.com/gogf/gf/database/gdb"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/frame/gmvc"
)
type xyuRoomColumns struct {
Id string
RoomNum string
}
type XyuRoomDao struct {
gmvc.M
DB gdb.DB
Table string
Columns xyuRoomColumns
}
var (
XyuRoom = XyuRoomDao{
M: g.DB("default").Model("xyu_room").Safe(),
DB: g.DB("default"),
Table: "xyu_room",
Columns: xyuRoomColumns{
Id: "id",
RoomNum: "room_num",
},
}
)
package internal
import (
"github.com/gogf/gf/database/gdb"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/frame/gmvc"
)
type xyuRoomFilesColumns struct {
Id string
RoomId string
Name string
}
type XyuRoomFilesDao struct {
gmvc.M
DB gdb.DB
Table string
Columns xyuRoomFilesColumns
}
var (
XyuRoomFiles = XyuRoomFilesDao{
M: g.DB("default").Model("xyu_room_files").Safe(),
DB: g.DB("default"),
Table: "xyu_room_files",
Columns: xyuRoomFilesColumns{
Id: "id",
RoomId: "room_id",
Name: "name",
},
}
)
package dao
import "ppt_server/app/dao/internal"
type xyuRoomDao struct {
internal.XyuRoomDao
}
var XyuRoom = xyuRoomDao{internal.XyuRoom}
package dao
import "ppt_server/app/dao/internal"
type xyuRoomFilesDao struct {
internal.XyuRoomFilesDao
}
var XyuRoomFile = xyuRoomFilesDao{
internal.XyuRoomFiles,
}
package model
import "ppt_server/app/model/internal"
type XyuRoom internal.XyuRoom
type XyuRoomFiles internal.XyuRoomFiles
// 客户端上传课件请求参数
type FileUploadRequest struct {
RoomNum string `p:"room_num" v:"required#房间号不能为空"`
Name string `p:"name" v:"required#课件名称不能为空"`
Nickanem string `p:"nickname" v:"required#用户昵称不能为空"`
Type int `p:"type" v:"required#类型不能为空"`
Url string `p:"url" v:"required#上传课件地址不能为空"`
Uuid string `p:"uuid" v:"required#上传者UUID不能为空"`
}
// web365解析文件返回信息
type UploadFileInfo struct {
FileName string `json:"FileName"`
FileSize int64 `json:"FileSize"`
PageCount int `jons:"PageCount"`
SlideCount int `json:"SlideCount"`
SheetCount int `json:"SheetCount"`
}
//OssPacked
type Packed struct {
FileName string `json:"fileName"`
Hash string `json:"json"`
ImagesName []string `json:"imagesName"`
OssImagesPath string `json:"ossImagesPath"`
ImageInfos [][]interface{} `json:"imageInfos"`
}
// 服务端通知返回信息
type NotifyResponse struct {
Code int64 `json:"code"`
Msg string `json:"msg"`
}
package internal
type XyuRoom struct {
Id int `orm:"id,primary" json:"id"`
RoomNum string `orm:"room_num" json:"room_num"`
}
package internal
type XyuRoomFiles struct {
Id int `orm:"id,primary" json:"id"`
RoomId int `orm:"room_id" json:"room_id"`
Name string `orm:"name" json:"name"`
}
package service
import (
"ppt_server/app/dao"
"ppt_server/app/model"
"ppt_server/packed"
"github.com/gogf/gf/frame/g"
)
var File = &fileService{
done: make(chan error),
ok: make(chan bool),
}
type fileService struct {
done chan error
ok chan bool
}
// 上传课件
func (f *fileService) Upload(r *model.FileUploadRequest) {
// 解析上传课件URL
parserURLObject, err := packed.ParserURL(r, f.done, f.ok)
if err != nil {
g.Log().Async().Errorf("Parser Url err: %s\n", err)
return
}
// 检查房间是否存在
var room model.XyuRoom
err = dao.XyuRoom.Where(dao.XyuRoom.Columns.RoomNum, r.RoomNum).Scan(&room)
if err != nil {
go func() { f.done <- err }()
g.Log().Async().Errorf("房间不存在, room_num: %s\n", r.RoomNum)
}
// 上传操作
go parserURLObject.Worker(err)
// 回调通知
n := packed.NewNotfiy()
select {
case <-f.done:
// 上传失败
n.Notify("/web/room_files_error", packed.FailGmap(r, parserURLObject))
return
case <-f.ok:
// 上传成功
count, err := dao.XyuRoomFile.Where(dao.XyuRoomFile.Columns.RoomId, room.Id).
Where(dao.XyuRoomFile.Columns.Name, r.Name).Count()
if err != nil {
g.Log().Async().Errorf("Mysql Err: %s\n", err)
return
}
// 数据库已经存在不需要通知
if count == 1 {
return
}
n.Notify("/web/room_files_add", packed.SuccessGmap(r, parserURLObject, room.Id))
}
}
package boot
import "github.com/gogf/gf/frame/g"
func init() {
g.Log().SetAsync(true)
}
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAo+8g8CvasfIwe4uToDzY8ir2rZoaBBV8EqM2gu+EwpmYnfBD
FYagyWvNDYNRYBKJgZuT/BU4f/dF0bFTFp0KwxcYDkhYE1TBNsnPqTNZGp0K2C9m
v2ATLyf+2DuVhW4etlQVnsqQBxPEoWCPmf4Mrta4xy83ZqS7BRBmi8avGyzhYjjB
hYLVuDAyOb+pDSGe9rpgcp0pyzpJ/4u8xLRO08CAUbyhN5l9ubrIBmV1F4PMhy1H
mmq26cJdMXcumzUZRebWtKK4xxZFteG8GNZIA0Oz8sk1RKjMgAVko7Uu6eR4rSlG
+R6pI79Npps3REIm1m8A3kMDCEmdDnl5q+ef3wIDAQABAoIBAHN4Mkk5epewsfmz
vM43TdB19r8dNon94CD4maLstySjL96/p2D4LTTzG8IS5zS2meiS/0+mWt+3+pPT
RWU+RKBaGfWle3RSVK4UxJK3umGGkGbqLINMVvb2QwloHs+XW0auP3RT1dNGV1Ac
RcoAKkrUr96NIYbJLXpJrRFzZ0/JzaKeHNB0OB8xQeWTVdM6liBgKhE8EMKqzA7E
Z3vZaB5Z4ezcYM+eKjKCkXkkhwc4AxibKdFdfBmdB6oFvMGoZjLbET/8CeOp6xKH
ovNEPohKpz0ewz932ZrpcikvnucXXhzhaxwmUmLF74WvVU+T5uIMjkj8jyylrUxw
kMzgufECgYEA9ew+hKtS8wWfnDqfURpDezjMueQF5/2kUVKuwsNhERLuXCe4XLFb
USAvHWrCiEqO0RA4Y+CybTS9kekMyC3lRHc+3otZ9ienp9BAcqA1T8UO2HEfFrfG
knUH9Xw7vjKwKBHPBARlnURqoiX5B9pjRs/Kya+19XVcAB7RNfbcvBsCgYEAqqbQ
b/3RYkM+fhy7xTITP6ommjRcnfI2RV/gGlt4jYM6/2GJ1PH3zOv+nhZfoffw/NYp
3A7zKfUe37frp5eYyoeZB1nB6Xo+aNsF0nSsc0x/Jms83gT5mfT3v9zUpOhe9FvH
iKgS0SYJVe9D5yuefLP1WNuYCy6/BLqE7nvyX40CgYBiD+s6EesItyRXMtUWjQd9
mj+gnHlycaTVPMgtJ6WMHmVn3/rXE23bYp8G9uxNVpWube5efVoIy/APv8N2Cz8R
1w79xMmBq3xiIVuhmZrIjUaHLkx8TZnkCsC6tehIxoOR5tAKxQoT9RUkRUoRRJcz
xGYTmHpRP5QJBEDeaOrKIwKBgBQ+zBWtOAz/S0es4v3nDe+MoR3EPoSiepvKXwzh
czDes74edTqlJi/Sg5d/sgLGJnnocnjf8Ss2IF6MNFHio0bLxXTgyieH0CWiblNk
ch0PozoMmOECGBaSwF2rtjKGOtWkmcx1nB3h9FOUmiqvuxKyStYq3yPcfN7zvdeJ
Ltz1AoGAI2P5xabnyBT2RU0pHth+YLg6SX0KNAPDuASTEUVcEFxftPmv90QRQhMU
2Ks6BpL+hwGxL6qu6heeq4PU9MVsFWCEZh9/igHDf0hHM60+euo/g8FHUkNn4/1q
2dd8CJM1uD/LSY0Cu7I3o2TOILHX9METraw6EWDq4iHnPy/tySI=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIGxTCCBa2gAwIBAgIQBlYKeyjVKIgKNuFr3A2gfzANBgkqhkiG9w0BAQsFADBf
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMR4wHAYDVQQDExVHZW9UcnVzdCBDTiBSU0EgQ0EgRzEw
HhcNMTkwOTE2MDAwMDAwWhcNMjEwOTE1MTIwMDAwWjB4MQswCQYDVQQGEwJDTjES
MBAGA1UECAwJ5YyX5Lqs5biCMS0wKwYDVQQKDCTljJfkuqzkuK3lhazmlZnogrLn
p5HmioDmnInpmZDlhazlj7gxCzAJBgNVBAsTAklUMRkwFwYDVQQDDBAqLm9mZmNu
Y2xvdWQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo+8g8Cva
sfIwe4uToDzY8ir2rZoaBBV8EqM2gu+EwpmYnfBDFYagyWvNDYNRYBKJgZuT/BU4
f/dF0bFTFp0KwxcYDkhYE1TBNsnPqTNZGp0K2C9mv2ATLyf+2DuVhW4etlQVnsqQ
BxPEoWCPmf4Mrta4xy83ZqS7BRBmi8avGyzhYjjBhYLVuDAyOb+pDSGe9rpgcp0p
yzpJ/4u8xLRO08CAUbyhN5l9ubrIBmV1F4PMhy1Hmmq26cJdMXcumzUZRebWtKK4
xxZFteG8GNZIA0Oz8sk1RKjMgAVko7Uu6eR4rSlG+R6pI79Npps3REIm1m8A3kMD
CEmdDnl5q+ef3wIDAQABo4IDYjCCA14wHwYDVR0jBBgwFoAUkZ9eMRWuEJ+tYMH3
wcyqSDQvDCYwHQYDVR0OBBYEFBdhbm8eOCcYqUMMraPc3XpinOcDMCsGA1UdEQQk
MCKCECoub2ZmY25jbG91ZC5jb22CDm9mZmNuY2xvdWQuY29tMA4GA1UdDwEB/wQE
AwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0
oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0dlb1RydXN0Q05SU0FDQUcx
LmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0dlb1RydXN0Q05S
U0FDQUcxLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIB
FhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAECAjBvBggrBgEF
BQcBAQRjMGEwIQYIKwYBBQUHMAGGFWh0dHA6Ly9vY3NwLmRjb2NzcC5jbjA8Bggr
BgEFBQcwAoYwaHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vR2VvVHJ1c3RDTlJT
QUNBRzEuY3J0MAkGA1UdEwQCMAAwggF9BgorBgEEAdZ5AgQCBIIBbQSCAWkBZwB2
ALvZ37wfinG1k5Qjl6qSe0c4V5UKq1LoGpCWZDaOHtGFAAABbTkJDU8AAAQDAEcw
RQIhAKxPVhYZl6lmgwkrHtPR6Tj+w07w8OEzzIi5tCux/F+NAiBzfajUaCWyHBkq
FmzUoZ2WRxhwDLJsGMfY/GVcLOf+XgB2AId1v+dZfPiMQ5lfvfNu/1aNR1Y2/0q1
YMG06v9eoIMPAAABbTkJDbUAAAQDAEcwRQIhAJ+oKOIjCEdBwBsdj9CYaJ1PBLoS
BfEAGv/rOy7t6rNoAiBdK24FvESSzbrN5hfPRCyZKTDQ0CCqsMn/5ztQ/z5iNAB1
AESUZS6w7s6vxEAH2Kj+KMDa5oK+2MsxtT/TM5a1toGoAAABbTkJDLoAAAQDAEYw
RAIgXX/xR8XI24dq8iZxhZBmLOLuo4ZbjOvdNz9wPV35eQQCICQu0+sZQ9aQXp9I
jRAnxxVtibIkystgYpgTn/VqMN/MMA0GCSqGSIb3DQEBCwUAA4IBAQBt0ddC3sUW
hRmTThB9ohImhH+pkwkDNRMF8YbOiDFuxFVBcvpKLjE+4BS0Tznkl7kMY/uCCmoo
PZeIdvpSIqVq6GmixWjcixOSXZ1gqiRHomqFOIYPi3emJbDV+J6c1rUzQvr8LFNb
Fen0xrT1ZNVK4W1GVM0givqjlvz0MI+8ds35HwuofzO8OUiJmcKziOTnlqHn/qNC
nFHlyCU33NYZw2YsZXZorJiPqoYAGSMcvunwKA7g0cZNMq9TXzOm9xDYrJ+wcEcU
uy0B6LfHkftgHlJ+7cOzQu4Gx8HI/eoJuTayifkjQQIAd4WgVmFLjDFkU0fZA5vL
S+8iHnMiCHok
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFGjCCBAKgAwIBAgIQCgRw0Ja8ihLIkKbfgm7sSzANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0xOTA2MjAxMjI3NThaFw0yOTA2MjAxMjI3NThaMF8xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xHjAcBgNVBAMTFUdlb1RydXN0IENOIFJTQSBDQSBHMTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALFJ+j1KeZVG4jzgQob23lQ8PJUNhY31ufZihuUx
hYc6HSU4Lw0fxfA43a9DpJl74M3E6F1ZRBOfJ+dWnaiyYD0PxRIQd4wJisti4Uad
vz61IYY/oQ/Elxk/X7GFDquYuxCSyBdHtTVMXCxFSvQ2C/7jWZFDfGGKKNoQSiJy
wDe8iiHbUOakLMmXmOTZyWJnFdR/TH5YNTiMKCNUPHAleG4IigGxDyL/gbwrdDNi
bDA4lUNhD0xNvPjQ8BNKqm5HWDvirUuHdC+4hpi0GJO34O3iiRV16YmWTuVFNboU
LDZ0+PQtctJnatpuZKPGyKX6jCpPvzzPw/EhNDlpEdrYHZMCAwEAAaOCAc4wggHK
MB0GA1UdDgQWBBSRn14xFa4Qn61gwffBzKpINC8MJjAfBgNVHSMEGDAWgBQD3lA1
VtFMu2bwo+IbG8OXsj3RVTAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYB
BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wMQYIKwYBBQUHAQEEJTAj
MCEGCCsGAQUFBzABhhVodHRwOi8vb2NzcC5kY29jc3AuY24wRAYDVR0fBD0wOzA5
oDegNYYzaHR0cDovL2NybC5kaWdpY2VydC1jbi5jb20vRGlnaUNlcnRHbG9iYWxS
b290Q0EuY3JsMIHOBgNVHSAEgcYwgcMwgcAGBFUdIAAwgbcwKAYIKwYBBQUHAgEW
HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYoGCCsGAQUFBwICMH4MfEFu
eSB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjb25zdGl0dXRlcyBhY2NlcHRhbmNl
IG9mIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCBsb2NhdGVkIGF0IGh0dHBz
Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9ycGEtdWEwDQYJKoZIhvcNAQELBQADggEBABfg
eXrxIrtlixBv+KMDeqKxtNJbZiLDzJBkGCd4HI63X5eS6BElJBn6mI9eYVrr7qOL
Tp7WiO02Sf1Yrpaz/ePSjZ684o89UAGpxOfbgVSMvo/a07n/220jUWLxzaJhQNLu
lACXwwWsxYf8twP8glkoIHnUUNTlhsyyl1ZzvVC4bDpI4hC6QkJGync1MNqYSMj8
tZbhQNw3HdSmcTO0Nc/J/pK2VZc6fFbKBgspmzdHc6jMKG2t4lisXEysS3wPcg0a
Nfr1Odl5+myh3MnMK08f6pTXvduLz+QZiIh8IYL+Z6QWgTZ9e2jnV8juumX1I8Ge
7cZdtNnTCB8hFfwGLUA=
-----END CERTIFICATE-----
appname = ppt_server
httpport = 80
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
sqlconn =
copyrequestbody = true
\ No newline at end of file
# HTTP Server
[server]
Address = ":80"
ServerRoot = "public"
ServerAgent = "gf-app"
LogPath = "/tmp/log/gf-app/server"
DumpRouterMap = true
# Logger.
[logger]
Path = "/tmp/log/gf-app"
Level = "all"
StdoutPrint = true
HeaderPrint = true
[notify]
url = "http://offcn-live-svc"
name = "offcn"
password = "123123"
[oss]
url = "https://xiaoyu-live.oss-cn-beijing-internal.aliyuncs.com"
point = "oss-cn-beijing.aliyuncs.com"
keyid = "LTAI1fMvVUPBXl2E"
serect = "cTAMLufmPFznfE0peur8oMmy2c5kvk"
# Database.
[database]
link = "mysql:video:vlty&AxMwT$lmLv6bN8dkDuBYlh%N5pe@tcp(rm-2zevlk47ul0ovuci80o.mysql.rds.aliyuncs.com:3306)/xyu"
debug = true
# Database logger.
[database.logger]
Path = "/tmp/log/gf-app/sql"
Level = "all"
Stdout = true
# Template.
[viewer]
Path = "template"
DefaultFile = "index.html"
Delimiters = ["${", "}"]
package controllers
import (
"github.com/astaxie/beego"
"ppt_server/models"
"ppt_server/upload"
)
type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
}
type UploadController struct {
beego.Controller
}
func (this *UploadController) newResponse(code int, msg string) {
response := &Response{
Code: code,
}
if msg != "" {
response.Msg = msg
}
this.Data["json"] = response
this.ServeJSON()
}
func (this *UploadController) Get() {
this.newResponse(200, "成功")
}
func (this *UploadController) Post() {
u := models.XyuSmallTempFiles{}
if err := this.ParseForm(&u); err != nil {
//handle error
this.newResponse(100, "参数绑定失败")
return
}
if u.RoomNum == "" || u.Uuid == "" || u.Url == "" {
this.newResponse(100, "参数不正确")
return
}
go upload.Upload(&u)
this.newResponse(200, "成功")
return
//fmt.Println(u)
}
\ No newline at end of file
......@@ -3,12 +3,8 @@ module ppt_server
go 1.12
require (
github.com/aliyun/aliyun-oss-go-sdk v2.0.6+incompatible
github.com/astaxie/beego v1.12.1
github.com/beego/bee v1.12.3
github.com/go-sql-driver/mysql v1.5.0
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
github.com/streadway/amqp v1.0.0
github.com/stretchr/objx v0.1.1 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
github.com/aliyun/aliyun-oss-go-sdk v2.1.9+incompatible // indirect
github.com/gogf/gf v1.16.4 // indirect
github.com/xxjwxc/gowp v0.0.0-20210520113007-57eb4693b12d // indirect
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
)
package library
import (
"io"
"net/http"
"os"
"time"
"github.com/gogf/gf/frame/g"
)
func Get(url string) ([]byte, error) {
response, err := g.Client().Timeout(30 * time.Second).Get(url)
if err != nil {
return nil, err
}
defer response.Close()
return response.ReadAll(), nil
}
func Download(file string, path string) error {
resp, err := http.Get(file)
if err != nil {
return err
}
defer resp.Body.Close()
// 创建一个文件用于保存
out, err := os.Create(path)
if err != nil {
return err
}
defer out.Close()
// 然后将响应流和文件流对接起来
_, err = io.Copy(out, resp.Body)
if err != nil && err == io.EOF {
return nil
}
if err != nil {
return err
}
return nil
}
package main
import (
"github.com/astaxie/beego"
_ "ppt_server/router"
_ "ppt_server/routers"
"github.com/gogf/gf/frame/g"
)
func main() {
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
}
beego.Run()
s := g.Server()
s.Run()
}
package middleware
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
"github.com/gogf/gf/util/gvalid"
"net/http"
)
// Recover异常恢复
func MiddlewareRecover(r *ghttp.Request) {
r.Middleware.Next()
if err := r.GetError(); err != nil {
r.Response.ClearBuffer()
switch e := err.(type) {
case gvalid.Error:
_ = r.Response.WriteJson(g.Map{
"code": http.StatusBadRequest,
"msg": e.FirstString(),
})
default:
_ = r.Response.WriteJson(g.Map{
"code": http.StatusInternalServerError,
"msg": err.Error(),
})
}
}
}
// CORS跨域
func MiddlewareCors(r *ghttp.Request) {
r.Response.CORSDefault()
r.Middleware.Next()
}
package models
import (
"fmt"
"log"
"ppt_server/utils"
"sync"
"github.com/astaxie/beego/orm"
_ "github.com/go-sql-driver/mysql"
)
var (
user string = utils.ConfigObject.DBuser
pass string = utils.ConfigObject.DBpass
host string = utils.ConfigObject.DBHost
port string = utils.ConfigObject.DBPort
dbname string = utils.ConfigObject.DBname
charset string = utils.ConfigObject.DBcharset
driver string = utils.ConfigObject.Driver
maxFreeConn int = utils.ConfigObject.MaxFreeLink
maxConn int = utils.ConfigObject.MaxLink
prefix string = utils.ConfigObject.DBprefix
)
type XyuRoom struct {
Id int `json:"id"`
RoomNum string `json:"room_num"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
Status int `json:"status"`
TeacherPassword string `json:"teacher_password"`
AssistantPassword string `json:"assistant_password"`
StudentPassword string `json:"student_password"`
HostPassword string `json:"host_password"`
SupervisePassword string `json:"supervise_password"`
IsRecording int
RoomType int `json:"room_type"`
ActualPush int
}
type XyuSmallRoom struct {
Id int
RoomId int
MaxPush int
RoomMode int
AllowMic int
}
type XyuSmallRoomWindow struct {
Id int
RoomNum string `json:"room_num"`
WId int `json:"wndindex"`
EId string `json:"e_id"`
PId string `json:"pid"`
Role string `json:"role"`
UserId string `json:"user_id"`
SetType int `json:"set_type"`
CreateTime string `json:"create_time"`
Status int
}
type XyuRoomUsers struct {
Id int `json:"id"`
Role string `json:"role"`
RoomNum string `json:"room_num"`
Token string `json:"token"`
}
type XyuSmallRoomPeople struct {
Id int
RoomNum string `pk;json:"room_num";`
Teacher int
Assistant int
Student int
Host int
Supervise int
}
type XyuSmallRoomRecord struct {
Id int
RoomNum string
Sessid string
Peerid string
RecordName string
TimeStamp string
}
type XyuSmallTempFiles struct {
Id int
RoomNum string `form:"room_num"`
Name string `form:"name"`
Nickanem string `form:"nickname"`
Type int `form:"type"`
Url string `form:"url"`
Time string `form:"time"'`
Uuid string `form:"uuid"`
Status int
}
type XyuRoomFiles struct {
Id int
RoomId int
Name string
}
var once sync.Once
func init() {
once.Do(func() {
init_mysql()
})
}
func init_mysql() {
dbConfStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s",
user, pass, host, port, dbname, charset)
log.Println("dbconf => ", dbConfStr)
_ = orm.RegisterDriver(driver, orm.DRMySQL)
err := orm.RegisterDataBase("default", driver, dbConfStr, maxFreeConn, maxConn)
if err != nil {
log.Println("db connect error => ", err)
return
}
orm.RegisterModel(new(XyuRoom), new(XyuRoomUsers), new(XyuSmallRoom), new(XyuSmallRoomWindow),
new(XyuSmallRoomPeople), new(XyuSmallRoomRecord), new(XyuSmallTempFiles), new(XyuRoomFiles))
//orm.Debug = true
log.Println("MySQL connect success")
}
package packed
import (
"mime"
)
type file struct {
ext string
}
// 解析doctype
func (f *file) getDocType() string {
switch f.ext {
case ".ppt", "pptx":
return "4"
case ".doc", "docx":
return "2"
case "xls", "xlsx":
return "3"
case ".pdf":
return "1"
default:
return "0"
}
}
// 获取文件mine
func (f *file) getMine() string {
_ = mime.AddExtensionType(".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation")
return mime.TypeByExtension(f.ext)
}
package packed
import (
"archive/zip"
"bytes"
"encoding/json"
"errors"
"fmt"
"image"
"image/jpeg"
"image/png"
"io/ioutil"
"net/url"
"os"
"path"
"strings"
"ppt_server/app/model"
"ppt_server/library"
"github.com/gogf/gf/frame/g"
"github.com/xxjwxc/gowp/workpool"
)
// 解析URL返回基本信息
type ObtainFile struct {
url string //上传URL
fileName string //上传文件名
NameHash string //文件名hash
ContentHash string //内容hash
DocType string //doc_type
MineType string //文件mine类型
fileInfoURL string //解析文件URL地址
uploadPath string //上传URL路径
DataPath string // 数据库存储Path
Link string //数据库存储link
FileSize int64
PageCount int
bucket *ossSdk
ok chan bool //上传传课件状态
err chan error // 上传课件失败Error
}
func ParserURL(r *model.FileUploadRequest, errChan chan error, ok chan bool) (*ObtainFile, error) {
u, err := url.Parse(r.Url)
if err != nil {
g.Log().Async().Error(err)
return nil, err
}
dataPath := u.EscapedPath()[1:]
slicePath := strings.Split(dataPath, "/")
if len(slicePath) < 4 {
g.Log().Async().Error(errors.New("上传URL格式不正确"))
return nil, errors.New("上传URL格式不正确")
}
f := &file{
ext: path.Ext(r.Name),
}
buecket, err := NewOss("xiaoyu-live")
if err != nil {
g.Log().Async().Error(err)
return nil, err
}
file := &ObtainFile{
url: r.Url,
fileName: r.Name,
NameHash: slicePath[3],
ContentHash: slicePath[2],
DocType: f.getDocType(),
MineType: f.getMine(),
bucket: buecket,
fileInfoURL: "http://doc.offcncloud.com/?info=0&ssl=1&furl=" + g.Cfg().GetString("oss.url") + u.EscapedPath(),
uploadPath: strings.Join(slicePath[0:len(slicePath)-1], "/") + "/",
DataPath: dataPath,
err: errChan,
ok: ok,
Link: strings.Replace(r.Url, "xiaoyu-live.oss-cn-beijing-internal.aliyuncs.com", "desktop.offcncloud.com", -1),
}
return file, nil
}
//从web365获取上传文件信息
func (f *ObtainFile) fileInfo() error {
fileBytes, err := library.Get(f.fileInfoURL)
if err != nil {
return err
}
var fileInfo model.UploadFileInfo
if err := json.Unmarshal(fileBytes, &fileInfo); err != nil {
return err
}
if fileInfo.FileSize != 0 {
f.FileSize = fileInfo.FileSize
}
switch {
case fileInfo.SlideCount != 0:
f.PageCount = fileInfo.SlideCount
case fileInfo.PageCount != 0:
f.PageCount = fileInfo.PageCount
case fileInfo.SheetCount != 0:
f.PageCount = fileInfo.SheetCount
}
return nil
}
func (f *ObtainFile) job(file *zip.File) ([]interface{}, error) {
fd, err := file.Open()
if err != nil {
return nil, err
}
defer fd.Close()
reqBody := []byte{}
reqBody, _ = ioutil.ReadAll(fd)
// 获取图片信息reader
imageReader := ioutil.NopCloser(bytes.NewBuffer(reqBody))
// 上传图片reader
fileReader := ioutil.NopCloser(bytes.NewBuffer(reqBody))
var img image.Image
fileSuffix := path.Ext(file.Name) //获取文件后缀
switch fileSuffix {
case ".png":
img, _ = png.Decode(imageReader)
case ".jpeg":
img, _ = jpeg.Decode(imageReader)
default:
return nil, errors.New("image ext is not found")
}
if img == nil {
return nil, errors.New("Image invalid")
}
var filenameOnly string
filenameOnly = strings.TrimRight(file.Name, fileSuffix)
filenameOnly = strings.Replace(filenameOnly, "p", "", -1)
fileName := fmt.Sprintf("%05s", filenameOnly) + fileSuffix
info := img.Bounds()
var imageInfo []interface{}
imageInfo = append(imageInfo, fileName)
imageInfo = append(imageInfo, info.Max.X)
imageInfo = append(imageInfo, info.Max.Y)
g.Log().Async().Infof("Upload picture file: %s Success", fileName)
return imageInfo, f.bucket.Upload(f.uploadPath+"images/"+fileName, fileReader)
}
func (f *ObtainFile) uploadPng(zipFileAddress string) ([][]interface{}, error) {
reader, err := zip.OpenReader(zipFileAddress)
if err != nil {
return nil, err
}
defer reader.Close()
pool := workpool.New(100)
var imageInfos [][]interface{}
for _, file := range reader.File {
pool.DoWait(func() error {
var err error
var imageInfo []interface{}
for i := 0; i < 3; i++ {
if imageInfo, err = f.job(file); err == nil {
imageInfos = append(imageInfos, imageInfo)
break
}
}
return err
})
}
if err = pool.Wait(); err != nil {
return nil, err
}
return imageInfos, nil
}
// 上传packed.json
func (f *ObtainFile) uploadPacked(imagesInfos [][]interface{}) error {
packed := model.Packed{
FileName: f.fileName,
Hash: f.ContentHash,
OssImagesPath: f.uploadPath + "images/",
ImageInfos: imagesInfos,
}
for i := 1; i <= f.PageCount; i++ {
packed.ImagesName = append(packed.ImagesName, fmt.Sprintf("%05d", i)+".png")
}
data, err := json.Marshal(packed)
if err != nil {
return err
}
return f.bucket.Upload(f.uploadPath+"packed.json", bytes.NewReader(data))
}
// 进行上传操作
func (f *ObtainFile) Worker(err error) {
if err != nil {
return
}
// 解析课件获取课件信息
if err = f.fileInfo(); err != nil {
g.Log().Async().Error(err)
f.err <- err
return
}
g.Log().Async().Infof("file: %s file info complete", f.fileName)
zipURL := fmt.Sprintf("http://doc.offcncloud.com/?info=1&words=%v&ssl=1&furl=%s",
f.PageCount, g.Cfg().GetString("oss.url")+"/"+f.DataPath)
// 下载ZIP包
zipURLAddress := "D:/" + f.ContentHash + ".zip"
if err = library.Download(zipURL, zipURLAddress); err != nil {
g.Log().Async().Error(err)
f.err <- err
return
}
g.Log().Async().Infof("file: %s Zip Donwload Complete", f.fileName)
// 解析ZIP包并上传图片到OSS
imagesInfos, err := f.uploadPng(zipURLAddress)
if err != nil {
g.Log().Async().Error(err)
f.err <- err
return
}
g.Log().Async().Infof("file: %s Upload picture Complete!", f.fileName)
// 上传packed.json到oss
if err := f.uploadPacked(imagesInfos); err != nil {
g.Log().Async().Error(err)
f.err <- err
return
}
g.Log().Async().Infof("filename == %s upload success!", f.fileName)
// 清理zip包
_ = os.Remove(zipURLAddress)
f.ok <- true
}
package packed
import (
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"regexp"
"strings"
"time"
"ppt_server/app/model"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/util/gconv"
)
type Notfiy struct {
token string
name string
password string
url string
c *http.Client
}
func NewNotfiy() *Notfiy {
jar, _ := cookiejar.New(nil)
return &Notfiy{
url: g.Cfg().GetString("notify.url"),
name: g.Cfg().GetString("notify.name"),
password: g.Cfg().GetString("notify.password"),
c: &http.Client{
Jar: jar,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
},
}
}
func (n *Notfiy) Post(url string, data g.Map) error {
res, err := n.request("POST", url, data)
if err != nil {
return err
}
var login model.NotifyResponse
if err := json.Unmarshal(res, &login); err != nil {
return err
}
if login.Code != 200 {
return errors.New(login.Msg)
}
return nil
}
func (n *Notfiy) Get(url string, data g.Map) ([]byte, error) {
return n.request("GET", url, data)
}
func (n *Notfiy) request(method, r_url string, data g.Map) ([]byte, error) {
vv := url.Values{}
for k, v := range data {
vv.Add(k, gconv.String(v))
}
vv.Encode()
reader := strings.NewReader(vv.Encode())
req, err := http.NewRequest(method, r_url, reader)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
res, err := n.c.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
return ioutil.ReadAll(res.Body)
}
func (n *Notfiy) setToken() error {
if err := n.Post(n.url+"/web/login", g.Map{
"name": n.name,
"password": n.password,
}); err != nil {
return err
}
// 获取Token
tokenTypes, err := n.Get(n.url+"/web/admin", nil)
if err != nil {
return err
}
re := regexp.MustCompile(`<meta name="csrf-token" content="([^"]+)">`)
token := re.FindAllSubmatch(tokenTypes, -1)
n.token = string(token[0][1])
return nil
}
// 上传失败通知
func (n *Notfiy) Notify(path string, data g.Map) {
var err error
if err = n.setToken(); err != nil {
g.Log().Async().Error(err)
return
}
data["_token"] = n.token
if err = n.Post(n.url+path, data); err != nil {
g.Log().Async().Errorf("notify fail, err : %s\n", err)
}
g.Log().Async().Infof("Notify Success!")
return
}
func FailGmap(r *model.FileUploadRequest, object *ObtainFile) g.Map {
return g.Map{
"code": 400,
"uuid": r.Uuid,
"room_num": r.RoomNum,
"path": object.DataPath,
}
}
func SuccessGmap(r *model.FileUploadRequest, object *ObtainFile, room_id int) g.Map {
data := g.Map{
"room_id": room_id,
"is_courseware": "1",
"private": "1",
"nickname": r.Nickanem,
"name": r.Name,
"time": time.Now().Format("2006-01-02 15:04:05"),
"uuid": r.Uuid,
"file_name_hash": object.NameHash,
"hash": object.ContentHash,
"doc_type": object.DocType,
"type": object.MineType,
"path": object.DataPath,
"files_size": object.FileSize,
"link": object.Link,
"page_count": object.PageCount,
}
switch r.Type {
case 1:
data["is_material"] = 1
case 2:
data["is_courseware"] = 1
case 3:
data["is_titlebook"] = 1
}
return data
}
package packed
import (
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/gogf/gf/frame/g"
"io"
)
type ossSdk struct {
bukectName string
bucket *oss.Bucket
}
func NewOss(bucket string) (*ossSdk, error) {
client, err := oss.New(g.Cfg().GetString("oss.point"),
g.Cfg().GetString("oss.keyid"), g.Cfg().GetString("oss.serect"))
if err != nil {
return nil, err
}
b, err := client.Bucket(bucket)
if err != nil {
return nil, err
}
return &ossSdk{bucket: b}, nil
}
func (sdk *ossSdk) Upload(path string, reader io.Reader) error {
return sdk.bucket.PutObject(path, reader)
}
package router
import (
"ppt_server/app/api"
"ppt_server/middleware"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
func init() {
s := g.Server()
s.Use(middleware.MiddlewareCors, middleware.MiddlewareRecover)
s.Group(`file`, func(group *ghttp.RouterGroup) {
group.ALL(`/`, api.File, "Index, Upload")
})
}
// @APIVersion 1.0.0
// @Title beego Test API
// @Description beego has a very cool tools to autogenerate documents for your API
// @Contact astaxie@gmail.com
// @TermsOfServiceUrl http://beego.me/
// @License Apache 2.0
// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html
package routers
import (
"encoding/json"
"fmt"
"ppt_server/controllers"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego"
"ppt_server/upload"
)
func init() {
beego.Router("/file/upload", &controllers.UploadController{})
beego.Post("/file/callback", func(ctx *context.Context) {
var mapFiles map[string]interface{}
var err error
fmt.Println("body === ", string(ctx.Input.RequestBody))
if err = json.Unmarshal(ctx.Input.RequestBody, &mapFiles); err != nil {
ctx.WriteString("Error " + err.Error())
return
}
if mapFiles["success"].(string) == "false" {
_ = upload.UpdateFileError("1", mapFiles["uuid"].(string), mapFiles["roomNum"].(string), mapFiles["path"].(string))
ctx.WriteString("Upload Fail")
return
}
if err = upload.CreateFileDataBase(mapFiles); err != nil {
_ = upload.UpdateFileError("2", mapFiles["uuid"].(string), mapFiles["roomNum"].(string), mapFiles["path"].(string))
ctx.WriteString("Error " + err.Error())
return
}
ctx.WriteString("Upload Ok")
})
}
/**
* @Authore: lifeifei
* @Date: 2021/1/25 10:47 上午
*/
package upload
import (
"encoding/json"
"fmt"
beeLogger "github.com/beego/bee/logger"
"github.com/streadway/amqp"
)
type RabbitMQ struct {
connection *amqp.Connection
channel *amqp.Channel
}
func (r *RabbitMQ) mqConnect() error {
var err error
RabbitUrl := fmt.Sprintf("amqp://%s:%s@%s:%d/",
"video",
"1fqH4WFR19uckgRyHzgISw",
"test-rmq.offcncloud.com/",
5672)
if r.connection, err = amqp.DialConfig(RabbitUrl, amqp.Config{Vhost: "v.ofc.office"}); err != nil {
beeLogger.Log.Errorf("RabbitMQ Server Connect Fail: %s", err)
return err
}
c, err := r.connection.Channel()
if err != nil {
beeLogger.Log.Errorf("Channel connet fail: %s", err)
return err
}
r.channel = c
beeLogger.Log.Success("RabbitMQ Server is running...")
return nil
}
func (r *RabbitMQ) mqClose() {
if r.channel != nil {
err := r.channel.Close()
if err != nil {
beeLogger.Log.Errorf("RabbitMQ Server Close Err: %s", err)
}
}
if r.connection != nil {
err := r.connection.Close()
if err != nil {
beeLogger.Log.Errorf("RabbitMQ Server Channel Close Err: %s", err)
}
}
}
func (r *RabbitMQ) Send(req map[string]interface{}) error {
defer r.mqClose()
if err := r.mqConnect(); err != nil {
return err
}
bytes, err := json.Marshal(req)
if err != nil {
return err
}
return r.channel.Publish("X.ofc.ppt2image", "RK.ofc.ppt2image", false, false, amqp.Publishing{
ContentType: "text/plain",
Body: bytes,
})
}
func Send(r map[string]interface{}) error {
mq := &RabbitMQ{}
return mq.Send(r)
}
/**
* @Authore: lifeifei
* @Date: 2021/1/25 10:11 上午
*/
package upload
import (
"github.com/astaxie/beego/orm"
beeLogger "github.com/beego/bee/logger"
"mime"
Qurl "net/url"
"path"
"ppt_server/models"
"strings"
"time"
)
type PPT struct {
request *models.XyuSmallTempFiles
}
func (p *PPT) Transform() (err error) {
maps := make(map[string]interface{})
o := orm.NewOrm()
var room models.XyuRoom
err = o.QueryTable("xyu_room").Filter("room_num", p.request.RoomNum).One(&room)
if err != nil {
beeLogger.Log.Errorf("获取房间信息失败:%s", err)
return
}
maps["url"] = p.request.Url
maps["room_id"] = room.Id
maps["id"] = time.Now().Unix()
maps["is_courseware"] = "1"
maps["private"] = "1"
maps["nickname"] = p.request.Nickanem
maps["name"] = p.request.Name
maps["time"] = time.Now().Format("2006-01-02 15:04:0")
maps["uuid"] = p.request.Uuid
switch p.request.Type {
case 1:
maps["is_material"] = 1
case 2:
maps["is_courseware"] = 1
case 3:
maps["is_titlebook"] = 1
}
objectName := p.request.Url[strings.Index(p.request.Url, "com/")+4:]
url, _ := Qurl.QueryUnescape(p.request.Url)
filename := path.Base(url)
ext := path.Ext(filename)
slice_path := strings.Split(objectName, "/")
maps["file_name_hash"] = slice_path[3]
maps["hash"] = slice_path[2]
var docType string
if strings.Contains(ext, "ppt") || strings.Contains(ext, "pptx") {
docType = "4"
} else if strings.Contains(ext, "doc") || strings.Contains(ext, "docx") {
docType = "2"
} else if strings.Contains(ext, "xls") || strings.Contains(ext, "xlsx") {
docType = "3"
} else if strings.Contains(ext, "pdf") {
docType = "1"
}
maps["doc_type"] = docType
_ = mime.AddExtensionType(".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation")
maps["type"] = mime.TypeByExtension(ext)
maps["path"] = objectName
link := strings.Replace(p.request.Url, "xiaoyu-live.oss-cn-beijing-internal.aliyuncs.com", "desktop.offcncloud.com", -1)
maps["link"] = link
if err = Send(maps); err != nil {
beeLogger.Log.Errorf("Send Error: %s", err)
_ = UpdateFileError("6", maps["uuid"].(string), maps["roomNum"].(string), objectName)
return
}
return nil
}
package upload
import (
"archive/zip"
"bytes"
"encoding/json"
"errors"
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/astaxie/beego/orm"
"github.com/rocketlaunchr/go-pool"
"github.com/xxjwxc/gowp/workpool"
"image"
"image/jpeg"
"image/png"
"io"
"io/ioutil"
"log"
"mime"
"net/http"
"net/http/cookiejar"
Qurl "net/url"
"os"
"path"
"ppt_server/models"
"regexp"
"strconv"
"strings"
"sync"
"time"
)
var (
WEBURL string = "http://offcn-live-svc"
//WEBURL string = "https://test-live.offcncloud.com"
once sync.Once
syncPool pool.Pool
)
const docUrl string = "http://doc.offcncloud.com/"
func init() {
once.Do(func() {
log.SetFlags(log.Lshortfile | log.LstdFlags)
syncPool = pool.New(10)
syncPool.SetFactory(func() interface{} {
return &bytes.Buffer{}
})
})
}
func Upload(v *models.XyuSmallTempFiles) {
go Down(v)
}
func Down(v *models.XyuSmallTempFiles) {
o := orm.NewOrm()
url, _ := Qurl.QueryUnescape(v.Url)
filename := path.Base(url)
filePath := "/data/files/" + filename
ext := path.Ext(filename)
objectName := v.Url[strings.Index(v.Url, "com/")+4:]
// 文件以及存在就不需要下载
if _, err := os.Stat(filePath); err != nil {
// Get the data
resp, err := http.Get(url)
if err != nil {
UpdateFileError("1", v.Uuid, v.RoomNum, objectName)
log.Println(err)
return
}
defer resp.Body.Close()
// 创建一个文件用于保存
out, err := os.Create(filePath)
if err != nil {
log.Println(err)
UpdateFileError("1", v.Uuid, v.RoomNum, objectName)
return
}
defer out.Close()
// 然后将响应流和文件流对接起来
_, err = io.Copy(out, resp.Body)
if err != nil {
log.Println(err)
UpdateFileError("1", v.Uuid, v.RoomNum, objectName)
return
}
}
var room models.XyuRoom
err := o.QueryTable("xyu_room").Filter("room_num", v.RoomNum).One(&room)
if err != nil {
log.Println(err)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
bucket, err := newOssClient()
if err != nil {
log.Println(err)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
file, err := os.Open(filePath)
if err != nil {
log.Println(err)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
defer file.Close()
room_file := make(map[string]interface{})
t := time.Now()
now := fmt.Sprintf("%02d-%02d-%02d %02d:%02d:%02d",
t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
slice_path := strings.Split(objectName, "/")
log.Println(slice_path[2])
room_file["room_id"] = room.Id
room_file["id"] = t.Unix()
room_file["is_courseware"] = "1"
room_file["private"] = "1"
room_file["nickname"] = v.Nickanem
room_file["name"] = v.Name
room_file["time"] = now
room_file["uuid"] = v.Uuid
if v.Type == 1 {
room_file["is_material"] = 1
} else if v.Type == 2 {
room_file["is_courseware"] = 1
} else if v.Type == 3 {
room_file["is_titlebook"] = 1
}
contentHash := slice_path[2]
room_file["file_name_hash"] = slice_path[3]
room_file["hash"] = contentHash
//获取文件后缀
var doc_type string
doc_type = "0"
if strings.Contains(ext, "ppt") || strings.Contains(ext, "pptx") {
doc_type = "4"
} else if strings.Contains(ext, "doc") || strings.Contains(ext, "docx") {
doc_type = "2"
} else if strings.Contains(ext, "xls") || strings.Contains(ext, "xlsx") {
doc_type = "3"
} else if strings.Contains(ext, "pdf") {
doc_type = "1"
}
room_file["doc_type"] = doc_type
_ = mime.AddExtensionType(".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation")
room_file["type"] = mime.TypeByExtension(ext)
fd, err := os.Open(filePath)
if err != nil {
log.Println(err)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
defer fd.Close()
log.Println("objectName == ", objectName)
objectPath := objectName[0:strings.LastIndex(objectName, "/")] + "/"
room_file["path"] = objectName
err = bucket.PutObject(objectName, fd)
if err != nil {
log.Println(err)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
furl := "https://xiaoyu-live.oss-cn-beijing-internal.aliyuncs.com/" + objectName
maps, err := getFileInfo(furl)
if err != nil {
log.Println(err)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
if e, ok := maps["error"]; ok {
log.Println(e)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
if _, ok := maps["FileSize"]; !ok {
log.Println(maps)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
if _, ok := maps["FileSize"].(float64); !ok {
log.Println(err)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
room_file["files_size"] = strconv.Itoa(int(maps["FileSize"].(float64)))
link := strings.Replace(v.Url, "xiaoyu-live.oss-cn-beijing-internal.aliyuncs.com", "desktop.offcncloud.com", -1)
room_file["link"] = link
wordFloat64 := getWords(maps)
room_file["page_count"] = wordFloat64
downUrl := fmt.Sprintf("http://doc.offcncloud.com/?info=1&words=%v&ssl=1&furl=%s",
wordFloat64, furl)
ch := make(chan bool)
go func() {
err := downloadFile(downUrl, contentHash, func(length, downLen int64) {
})
if err == nil {
ch <- true
} else {
UpdateFileError("3", v.Uuid, v.RoomNum, objectName)
return
}
}()
<-ch
reader, err := zip.OpenReader("/data/files/" + contentHash + ".zip")
if err != nil {
log.Println("5===", err)
UpdateFileError("4", v.Uuid, v.RoomNum, objectName)
return
}
Pool := workpool.New(100)
var imageInfos [][]interface{}
for _, file := range reader.File {
Pool.DoWait(func() error {
log.Printf("file = %s \n", file.Name)
var err error
for i := 0; i < 3; i++ {
if imageInfo, err := pdfThumbnail(objectPath, file, bucket); err == nil {
imageInfos = append(imageInfos, imageInfo)
break
} else {
log.Println("err = ", err)
UpdateFileError("4", v.Uuid, v.RoomNum, objectName)
return err
}
}
return err
})
}
log.Println("imageInfos == ", imageInfos)
err = Pool.Wait()
if err != nil {
UpdateFileError("5", v.Uuid, v.RoomNum, objectName)
log.Println(err)
return
}
defer reader.Close()
go func() {
err := uploadPacked(bucket, filename, contentHash, objectPath,
wordFloat64, imageInfos)
if err != nil {
UpdateFileError("6", v.Uuid, v.RoomNum, objectName)
log.Println(err)
return
}
}()
//调用服务端接口写入数据库
var roomFile models.XyuRoomFiles
err = o.QueryTable("xyu_room_files").Filter("room_id", room.Id).Filter("name", filename).One(&roomFile)
if err == orm.ErrNoRows {
err = CreateFileDataBase(room_file)
if err != nil {
log.Println("err==", err)
UpdateFileError("2", v.Uuid, v.RoomNum, objectName)
return
}
}
elapsed := time.Since(t)
log.Println("filename == ", filename, " 上传成功, 上传耗时 == ", elapsed)
// 删除压缩包和删除文件
defer os.Remove(filePath)
defer os.Remove("/data/files/" + contentHash + ".zip")
return
}
func webToken() (*http.Client, string, error) {
jar, err := cookiejar.New(nil)
if err != nil {
return &http.Client{}, "", err
}
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
Jar: jar,
}
payload := strings.NewReader("name=offcn&password=123123")
req, err := http.NewRequest("POST", WEBURL+"/web/login", payload)
if err != nil {
return &http.Client{}, "", err
}
req.Header.Add("content-type", "multipart/form-data")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, err := client.Do(req)
if err != nil {
log.Println("token请求失败", err)
return &http.Client{}, "", err
}
bodys, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Println("获取数据失败", err)
return &http.Client{}, "", err
}
defer res.Body.Close()
response := string(bodys)
map2 := make(map[string]interface{})
err = json.Unmarshal([]byte(response), &map2)
if err != nil {
return &http.Client{}, "", err
}
log.Println("获取token == ", map2)
if _, ok := map2["code"]; !ok {
return &http.Client{}, "", errors.New("登录失败")
}
if _, ok := map2["code"].(float64); !ok {
return &http.Client{}, "", errors.New("登录失败")
}
if int(map2["code"].(float64)) == 200 {
//登录成功获取token
t_res, err := client.Get(WEBURL + "/web/admin")
if err != nil {
log.Println("token无效", err)
return &http.Client{}, "", err
}
defer t_res.Body.Close()
body, err := ioutil.ReadAll(t_res.Body)
if err != nil {
return &http.Client{}, "", err
}
re := regexp.MustCompile(`<meta name="csrf-token" content="([^"]+)">`)
token := re.FindAllStringSubmatch(string(body), -1)[0][1]
return client, token, nil
} else {
return &http.Client{}, "", errors.New("登录失败")
}
}
func UpdateFileError(code, uuid, room_num, path string) error {
vv := Qurl.Values{}
vv.Add("code", code)
vv.Add("uuid", uuid)
vv.Add("room_num", room_num)
vv.Add("path", path)
client, token, err := webToken()
if err != nil {
log.Println("token 获取失败", err)
return err
}
vv.Add("_token", token)
body := vv.Encode()
payload := strings.NewReader(body)
req, err := http.NewRequest("POST", WEBURL+"/web/room_files_error", payload)
if err != nil {
log.Println(err)
return err
}
req.Header.Add("content-type", "multipart/form-data")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, err := client.Do(req)
if err != nil {
log.Println(err)
return err
}
defer res.Body.Close()
post_body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Println(err)
return err
}
map2 := make(map[string]interface{})
err = json.Unmarshal(post_body, &map2)
if err != nil {
log.Println(err)
return err
}
log.Println("room_files_err response = ", map2)
if _, ok := map2["code"]; !ok {
return errors.New("消息下发失败")
}
if _, ok := map2["code"].(float64); !ok {
return errors.New("消息下发失败")
}
if int(map2["code"].(float64)) != 200 {
log.Println("消息下发失败")
return errors.New("消息下发失败")
}
return nil
}
func CreateFileDataBase(room_file map[string]interface{}) error {
vv := Qurl.Values{}
for k, v := range room_file {
vv.Add(k, fmt.Sprintf("%v", v))
}
client, token, err := webToken()
if err != nil {
log.Println("token 获取失败", err)
return err
}
vv.Add("_token", token)
body := vv.Encode()
payload := strings.NewReader(body)
req, err := http.NewRequest("POST", WEBURL+"/web/room_files_add", payload)
if err != nil {
log.Println(err)
return err
}
req.Header.Add("content-type", "multipart/form-data")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
res, err := client.Do(req)
if err != nil {
log.Println(err)
return err
}
defer res.Body.Close()
post_body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Println(err)
return err
}
map2 := make(map[string]interface{})
err = json.Unmarshal(post_body, &map2)
if err != nil {
log.Println(err)
return err
}
log.Println("room_files response = ", map2)
if _, ok := map2["code"]; !ok {
return errors.New("上传失败")
}
if _, ok := map2["code"].(float64); !ok {
return errors.New("上传失败")
}
if int(map2["code"].(float64)) != 200 {
return errors.New("上传失败")
}
return nil
}
func pdfThumbnail(objectPath string, file *zip.File, bucket *oss.Bucket) ([]interface{}, error) {
fc, err := file.Open()
if err != nil {
return nil, err
}
defer fc.Close()
//item := syncPool.Borrow()
//defer item.Return()
//item.MarkAsInvalid()
//
//buf := item.Item.(*bytes.Buffer)
var img image.Image
fileSuffix := path.Ext(file.Name) //获取文件后缀
switch fileSuffix {
case ".png":
img, _ = png.Decode(fc)
case ".jpeg":
img, _ = jpeg.Decode(fc)
default:
return nil, errors.New("image ext is not found")
}
//if err = webp.Encode(buf, img, &webp.Options{Lossless: true}); err != nil {
// return nil, err
//}
//r := bytes.NewReader(buf.Bytes())
objectPathName := objectPath + "images/"
var filenameOnly string
filenameOnly = strings.TrimRight(file.Name, fileSuffix)
filenameOnly = strings.Replace(filenameOnly, "p", "", -1)
fileName := fmt.Sprintf("%05s", filenameOnly) + fileSuffix
info := img.Bounds()
var imageInfo []interface{}
imageInfo = append(imageInfo, fileName)
imageInfo = append(imageInfo, info.Max.X)
imageInfo = append(imageInfo, info.Max.Y)
fc1, err := file.Open()
if err != nil {
return nil, err
}
defer fc1.Close()
return imageInfo, bucket.PutObject(objectPathName+fileName, fc1)
}
func uploadPacked(bucket *oss.Bucket, filename, contentHash,
objectPath string, word float64, imageInfos [][]interface{}) error {
type packed struct {
FileName string `json:"fileName"`
Hash string `json:"hash"`
ImagesName []string `json:"imagesName"`
OssImagesPath string `json:"ossImagesPath"`
ImageInfos [][]interface{} `json:"imageInfos"`
}
p := packed{
FileName: filename,
Hash: contentHash,
OssImagesPath: objectPath + "images/",
ImageInfos: imageInfos,
}
for i := 1; i <= int(word); i++ {
p.ImagesName = append(p.ImagesName, fmt.Sprintf("%05d", i)+".png")
}
log.Println("imageInfos == ", imageInfos)
data, err := json.Marshal(p)
if err != nil {
return err
}
err = bucket.PutObject(objectPath+"packed.json",
strings.NewReader(string(data)))
if err != nil {
return err
}
return nil
}
func getWords(maps map[string]interface{}) float64 {
if word, ok := maps["SlideCount"]; ok {
return word.(float64)
}
if word, ok := maps["PageCount"]; ok {
return word.(float64)
}
if word, ok := maps["SheetCount"]; ok {
return word.(float64)
}
return float64(0)
}
func getFileInfo(ossFile string) (map[string]interface{}, error) {
url := docUrl + "?info=0&ssl=1&furl=" + ossFile
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var maps map[string]interface{}
err = json.Unmarshal(b, &maps)
if err != nil {
return nil, err
}
return maps, nil
}
func newOssClient() (*oss.Bucket, error) {
client, err := oss.New("oss-cn-beijing-internal.aliyuncs.com",
"LTAI1fMvVUPBXl2E", "cTAMLufmPFznfE0peur8oMmy2c5kvk")
if err != nil {
return nil, err
}
bucket, err := client.Bucket("xiaoyu-live")
if err != nil {
return nil, err
}
return bucket, nil
}
func downloadFile(url, contentHash string, fb func(length, downLen int64)) error {
var (
fsize int64
buf = make([]byte, 32*1024)
written int64
)
//创建一个http client
client := new(http.Client)
//get方法获取资源
resp, err := client.Get(url)
log.Println(url)
if err != nil {
log.Println(err)
return err
}
//读取服务器返回的文件大小
fsize, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 32)
if err != nil {
log.Println(err)
return err
}
//创建文件
file, err := os.Create("/data/files/" + contentHash + ".zip")
if err != nil {
log.Println(err)
return err
}
defer file.Close()
if resp.Body == nil {
log.Println(err)
return errors.New("body is null")
}
defer resp.Body.Close()
//下面是 io.copyBuffer() 的简化版本
for {
//读取bytes
nr, er := resp.Body.Read(buf)
if nr > 0 {
//写入bytes
nw, ew := file.Write(buf[0:nr])
//数据长度大于0
if nw > 0 {
written += int64(nw)
}
//写入出错
if ew != nil {
err = ew
break
}
//读取是数据长度不等于写入的数据长度
if nr != nw {
err = io.ErrShortWrite
break
}
}
if er != nil {
if er != io.EOF {
err = er
}
break
}
//没有错误了快使用 callback
fb(fsize, written)
}
return err
}
package utils
const (
ROOM_FIELD = "room_num"
CREATEROOM = "auth-createroom"
JOINROOM = "auth-push"
LEAVEROOM = "auth-unpush"
LEAVEPOD = "auth-podexit"
LEAVEEDGEID = "auth-edgeexit"
RECORDCREATE = "record-create"
TIME_FORMAT = "2006-01-02 15:04:05"
TABLE_XYU_ROOM_USERS = "xyu_room_users"
TABLE_XYU_ROOM = "xyu_room"
TABLE_XYU_SMAIL_ROOM = "xyu_small_room"
TABLE_XYU_SMAIL_ROOM_WINDOW = "xyu_small_room_window"
TABLE_XYU_SMALL_PEOPLE = "xyu_small_room_people"
TABLE_XYU_SMALL_RECORD = "xyu_small_room_record"
TEACHER = "teacher"
ASSISTANT = "assistant"
STUDENT = "student"
HOST = "host"
SUPERVISE = "supervise"
)
package utils
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"time"
)
type RabbitMqConf struct {
Username string
Password string
Host string
Port int
ConfFilePath string
Driver string
DBHost string
DBPort string
DBpass string
DBuser string
DBname string
DBcharset string
DBprefix string
ReconnectionTime time.Duration
MaxFreeLink int
MaxLink int
}
var ConfigObject *RabbitMqConf
func (r *RabbitMqConf) Reload() {
if confFileExists, _ := PathExists(r.ConfFilePath); !confFileExists {
fmt.Println("Config File ", r.ConfFilePath, " is not exist!!")
return
}
data, err := ioutil.ReadFile(r.ConfFilePath)
if err != nil {
panic(err)
}
//将json数据解析到struct中
err = json.Unmarshal(data, r)
if err != nil {
panic(err)
}
}
//判断一个文件是否存在
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
func init() {
//ConfigObject = &RabbitMqConf{
// Host: os.Getenv("rb_host"),
// Username: os.Getenv("rb_user"),
// Password: os.Getenv("rb_pass"),
// DBHost: os.Getenv("write_sql"),
// DBuser: os.Getenv("write_user"),
// DBpass: os.Getenv("write_pass"),
// Port: 5672,
// ConfFilePath: "conf/rmq.conf",
// ReconnectionTime: 10 * time.Second,
//}
//ConfigObject.Reload()
ConfigObject = &RabbitMqConf{
DBHost: "rm-2zevlk47ul0ovuci80o.mysql.rds.aliyuncs.com",
DBuser: "video",
DBpass: "vlty&AxMwT$lmLv6bN8dkDuBYlh%N5pe",
DBPort: "3306",
DBname: "xyu",
Driver: "mysql",
DBcharset: "utf8",
Username: "admin",
Password: "admin",
Host: "192.168.10.156",
Port: 5672,
ConfFilePath: "conf/rmq.conf",
ReconnectionTime: 1 * time.Second,
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment