Commit cb54c46f by Li Feifei

测试完成

parents
# Default ignored files
/workspace.xml
\ No newline at end of file
<?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
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ppt_server.iml" filepath="$PROJECT_DIR$/.idea/ppt_server.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ 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
appname = ppt_server
httpport = 8081
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
sqlconn =
\ No newline at end of file
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) Post() {
u := models.XyuSmallTempFiles{}
if err := this.ParseForm(&u); err != nil {
//handle error
this.newResponse(100, "参数绑定失败")
return
}
if u.RoomNum == "" || u.Uuid == "" || u.Url == "" || u.Type == 0 {
this.newResponse(100, "参数不正确")
return
}
go upload.Upload(&u)
this.newResponse(200, "成功")
return
//fmt.Println(u)
}
\ No newline at end of file
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/go-sql-driver/mysql v1.4.1
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
)
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
github.com/aliyun/aliyun-oss-go-sdk v2.0.6+incompatible h1:ZDgadcjGIrbHMBLSqQVHkMOdNd/jF6bsSRJd/Ysxlos=
github.com/aliyun/aliyun-oss-go-sdk v2.0.6+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/astaxie/beego v1.12.1 h1:dfpuoxpzLVgclveAXe4PyNKqkzgm5zF4tgF2B3kkM2I=
github.com/astaxie/beego v1.12.1/go.mod h1:kPBWpSANNbSdIqOc8SUL9h+1oyBMZhROeYsXQDbidWQ=
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20200117065230-39095c1d176c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
package main
import (
"archive/zip"
"crypto/md5"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
"io"
"io/ioutil"
"mime"
"net/http"
"net/http/cookiejar"
"os"
"path"
"ppt_server/models"
_ "ppt_server/routers"
"regexp"
Qurl "net/url"
"strconv"
"strings"
"time"
)
var (
WEBURL string = "http://offcn-live-svc"
client *http.Client
token string
)
const docUrl string = "http://doc.offcncloud.com/"
func main() {
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
}
beego.Run()
}
//func main() {
//tick := time.NewTicker(30 * time.Minute)
//upload()
//for {
// select {
// case <-tick.C:
// upload()
// }
//}
//}
func ptoken() {
qclient, qtoken, err := webToken()
client = qclient
token = qtoken
if err != nil {
fmt.Println(err)
return
}
}
func upload() {
o := orm.NewOrm()
var files []*models.XyuSmallTempFiles
_, _ = o.QueryTable("xyu_small_temp_files").Filter("status", 1).All(&files)
if len(files) > 0 {
ptoken()
for _, v := range files {
go Down(v)
}
}
}
func Down(v *models.XyuSmallTempFiles) {
o := orm.NewOrm()
url, _ := Qurl.QueryUnescape(v.Url)
filename := path.Base(url)
filePath := "/data/files/" + filename
// 文件以及存在就不需要下载
if _, err := os.Stat(filePath); err != nil {
// Get the data
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
// 创建一个文件用于保存
out, err := os.Create(filePath)
if err != nil {
fmt.Println(err)
return
}
defer out.Close()
// 然后将响应流和文件流对接起来
_, err = io.Copy(out, resp.Body)
if err != nil {
fmt.Println(err)
return
}
}
var room models.XyuRoom
err := o.QueryTable("xyu_room").Filter("room_num", v.RoomNum).One(&room)
if err != nil {
fmt.Println(err)
return
}
bucket, err := newOssClient()
if err != nil {
fmt.Println(err)
return
}
file, err := os.Open(filePath)
if err != nil {
fmt.Println(err)
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())
room_file["room_id"] = room.Id
room_file["id"] = t.Unix()
room_file["is_courseware"] = "1"
room_file["private"] = "1"
room_file["nickname"] = "助教"
room_file["name"] = filename
room_file["time"] = now
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, _ := fileContentHash(file)
fileHash := []byte(filename)
fileHashName := fmt.Sprintf("%x", sha1.Sum(fileHash))
room_file["file_name_hash"] = fileHashName
room_file["hash"] = contentHash
//获取文件后缀
ext := path.Ext(filename)
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 {
fmt.Println(err)
return
}
defer fd.Close()
objectPath := "documents/" + v.RoomNum + "/" + contentHash + "/" + fileHashName + "/"
objectName := objectPath + contentHash + ext
fmt.Println("objectName == ", objectName)
room_file["path"] = objectPath
err = bucket.PutObject(objectName, fd)
if err != nil {
fmt.Println(err)
return
}
furl := "https://xiaoyu-live.oss-cn-beijing.aliyuncs.com/" + objectName
maps, err := getFileInfo(furl)
if err != nil {
fmt.Println(err)
return
}
room_file["files_size"] = strconv.Itoa(int(maps["FileSize"].(float64)))
room_file["link"] = furl
wordFloat64 := getWords(maps)
downUrl := fmt.Sprintf("http://doc.offcncloud.com/?info=1&words=%v&ssl=1&furl=%s",
wordFloat64, furl)
go func() {
err := uploadPacked(bucket, filename, contentHash, objectPath,
wordFloat64)
if err != nil {
fmt.Println(err)
return
}
}()
ch := make(chan bool)
go func() {
err := downloadFile(downUrl, func(length, downLen int64) {
})
if err == nil {
ch <- true
}
}()
<-ch
var uploadImageCount float64
reader, err := zip.OpenReader( "/data/files/" + contentHash + ".zip")
if err != nil {
fmt.Println(err)
return
}
ch1 := make(chan bool)
for _, file := range reader.File {
go func(file *zip.File) {
err := pdfThumbnail(objectPath, file, bucket)
if err != nil {
fmt.Println(objectPath + file.Name + "上传失败")
// 上传缩略图失败,重试3次
for i := 0; i < 3; i++ {
err = pdfThumbnail(objectPath, file, bucket)
if err == nil {
ch1 <- true
return
}
}
ch1 <- false
return
} else {
ch1 <- true
return
}
}(file)
}
for i := 0; i < int(wordFloat64); i++ {
t := <-ch1
if t {
uploadImageCount++
}
}
defer reader.Close()
fmt.Println(uploadImageCount, wordFloat64)
if uploadImageCount != wordFloat64 {
fmt.Println("上传失败")
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 {
fmt.Println(err)
return
}
}
elapsed := time.Since(t)
fmt.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 {
return &http.Client{}, "", err
}
bodys, err := ioutil.ReadAll(res.Body)
if err != nil {
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
}
if int(map2["code"].(float64)) == 200 {
//登录成功获取token
t_res, err := client.Get(WEBURL + "/web/admin")
if err != nil {
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 createFileDataBase(room_file map[string]interface{}) error {
vv := Qurl.Values{}
for k, v := range room_file {
vv.Add(k, fmt.Sprintf("%v", v))
}
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 {
fmt.Println("123")
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 {
return err
}
defer res.Body.Close()
post_body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println("456")
return err
}
map2 := make(map[string]interface{})
err = json.Unmarshal(post_body, &map2)
if err != nil {
fmt.Println("678")
return err
}
if int(map2["code"].(float64)) != 200 {
return errors.New("上传失败")
}
return nil
}
func pdfThumbnail(objectPath string, file *zip.File, bucket *oss.Bucket) error {
fc, err := file.Open()
if err != nil {
return err
}
defer fc.Close()
objectPathName := objectPath + "images/"
var fileSuffix string
fileSuffix = path.Ext(file.Name) //获取文件后缀
var filenameOnly string
filenameOnly = strings.TrimRight(file.Name, fileSuffix)
filenameOnly = strings.Replace(filenameOnly, "p", "", -1)
fileName := fmt.Sprintf("%05s", filenameOnly) + fileSuffix
return bucket.PutObject(objectPathName+fileName, fc)
}
func uploadPacked(bucket *oss.Bucket, filename, contentHash,
objectPath string, word float64) error {
type packed struct {
FileName string `json:"fileName"`
Hash string `json:"hash"`
ImagesName []string `json:"imagesName"`
OssImagesPath string `json:"ossImagesPath"`
}
p := packed{
FileName: filename,
Hash: contentHash,
OssImagesPath: objectPath + "images/",
}
for i := 1; i <= int(word); i++ {
p.ImagesName = append(p.ImagesName, fmt.Sprintf("%05d", i)+".png")
}
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.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 fileContentHash(file io.Reader) (string, []byte) {
b, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println(err)
}
hash := md5.New()
io.WriteString(hash, string(b))
result := hash.Sum(nil)
return fmt.Sprintf("%s", hex.EncodeToString(result)), b
}
func downloadFile(url 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)
fmt.Println(url)
if err != nil {
return err
}
//读取服务器返回的文件大小
fsize, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 32)
if err != nil {
fmt.Println(err)
}
//创建文件
var filenameWithSuffix string
filenameWithSuffix = path.Base(url) //获取文件名带后缀
var fileSuffix string
fileSuffix = path.Ext(filenameWithSuffix) //获取文件后缀
var filenameOnly string
filenameOnly = strings.Replace(filenameWithSuffix, fileSuffix, ".zip", -1) //获取文件名
file, err := os.Create("/data/files/" + filenameOnly)
if err != nil {
return err
}
defer file.Close()
if resp.Body == nil {
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 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"`
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")
}
File added
// @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 (
"ppt_server/controllers"
"github.com/astaxie/beego"
)
func init() {
beego.Router("/file/upload", &controllers.UploadController{})
}
package upload
import (
"archive/zip"
"crypto/md5"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/astaxie/beego/orm"
"io"
"io/ioutil"
"mime"
"net/http"
"net/http/cookiejar"
"os"
"path"
"ppt_server/models"
"regexp"
Qurl "net/url"
"strconv"
"strings"
"time"
)
var (
//WEBURL string = "http://offcn-live-svc"
WEBURL string = "https://test-live.offcncloud.com"
client *http.Client
token string
)
const docUrl string = "http://doc.offcncloud.com/"
//func main() {
//tick := time.NewTicker(30 * time.Minute)
//upload()
//for {
// select {
// case <-tick.C:
// upload()
// }
//}
//}
func ptoken() {
qclient, qtoken, err := webToken()
client = qclient
token = qtoken
println("token ===", token)
if err != nil {
fmt.Println(err)
return
}
}
func Upload(v *models.XyuSmallTempFiles) {
//ptoken()
go Down(v)
}
func Down(v *models.XyuSmallTempFiles) {
o := orm.NewOrm()
url, _ := Qurl.QueryUnescape(v.Url)
filename := path.Base(url)
filePath := "/data/files/" + filename
// 文件以及存在就不需要下载
if _, err := os.Stat(filePath); err != nil {
// Get the data
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
// 创建一个文件用于保存
out, err := os.Create(filePath)
if err != nil {
fmt.Println(err)
return
}
defer out.Close()
// 然后将响应流和文件流对接起来
_, err = io.Copy(out, resp.Body)
if err != nil {
fmt.Println(err)
return
}
}
var room models.XyuRoom
err := o.QueryTable("xyu_room").Filter("room_num", v.RoomNum).One(&room)
if err != nil {
fmt.Println(err)
return
}
bucket, err := newOssClient()
if err != nil {
fmt.Println(err)
return
}
file, err := os.Open(filePath)
if err != nil {
fmt.Println(err)
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())
room_file["room_id"] = room.Id
room_file["id"] = t.Unix()
room_file["is_courseware"] = "1"
room_file["private"] = "1"
room_file["nickname"] = "助教"
room_file["name"] = filename
room_file["time"] = now
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, _ := fileContentHash(file)
fileHash := []byte(filename)
fileHashName := fmt.Sprintf("%x", sha1.Sum(fileHash))
room_file["file_name_hash"] = fileHashName
room_file["hash"] = contentHash
//获取文件后缀
ext := path.Ext(filename)
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 {
fmt.Println(err)
return
}
defer fd.Close()
objectPath := "documents/" + v.RoomNum + "/" + contentHash + "/" + fileHashName + "/"
objectName := objectPath + contentHash + ext
fmt.Println("objectName == ", objectName)
room_file["path"] = objectPath
err = bucket.PutObject(objectName, fd)
if err != nil {
fmt.Println(err)
return
}
furl := "https://xiaoyu-live.oss-cn-beijing.aliyuncs.com/" + objectName
maps, err := getFileInfo(furl)
if err != nil {
fmt.Println(err)
return
}
room_file["files_size"] = strconv.Itoa(int(maps["FileSize"].(float64)))
room_file["link"] = furl
wordFloat64 := getWords(maps)
downUrl := fmt.Sprintf("http://doc.offcncloud.com/?info=1&words=%v&ssl=1&furl=%s",
wordFloat64, furl)
go func() {
err := uploadPacked(bucket, filename, contentHash, objectPath,
wordFloat64)
if err != nil {
fmt.Println(err)
return
}
}()
ch := make(chan bool)
go func() {
err := downloadFile(downUrl, func(length, downLen int64) {
})
if err == nil {
ch <- true
}
}()
<-ch
var uploadImageCount float64
reader, err := zip.OpenReader( "/data/files/" + contentHash + ".zip")
if err != nil {
fmt.Println(err)
return
}
ch1 := make(chan bool)
for _, file := range reader.File {
go func(file *zip.File) {
err := pdfThumbnail(objectPath, file, bucket)
if err != nil {
fmt.Println(objectPath + file.Name + "上传失败")
// 上传缩略图失败,重试3次
for i := 0; i < 3; i++ {
err = pdfThumbnail(objectPath, file, bucket)
if err == nil {
ch1 <- true
return
}
}
ch1 <- false
return
} else {
ch1 <- true
return
}
}(file)
}
for i := 0; i < int(wordFloat64); i++ {
t := <-ch1
if t {
uploadImageCount++
}
}
defer reader.Close()
fmt.Println(uploadImageCount, wordFloat64)
if uploadImageCount != wordFloat64 {
fmt.Println("上传失败")
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 {
fmt.Println("err==", err)
return
}
}
elapsed := time.Since(t)
fmt.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 {
fmt.Println("token请求失败", err)
return &http.Client{}, "", err
}
bodys, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.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
}
if int(map2["code"].(float64)) == 200 {
//登录成功获取token
t_res, err := client.Get(WEBURL + "/web/admin")
if err != nil {
fmt.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 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 {
fmt.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 {
fmt.Println("123")
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 {
fmt.Println("5555")
return err
}
defer res.Body.Close()
post_body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println("456")
return err
}
map2 := make(map[string]interface{})
err = json.Unmarshal(post_body, &map2)
if err != nil {
fmt.Println("678")
return err
}
if int(map2["code"].(float64)) != 200 {
return errors.New("上传失败")
}
return nil
}
func pdfThumbnail(objectPath string, file *zip.File, bucket *oss.Bucket) error {
fc, err := file.Open()
if err != nil {
return err
}
defer fc.Close()
objectPathName := objectPath + "images/"
var fileSuffix string
fileSuffix = path.Ext(file.Name) //获取文件后缀
var filenameOnly string
filenameOnly = strings.TrimRight(file.Name, fileSuffix)
filenameOnly = strings.Replace(filenameOnly, "p", "", -1)
fileName := fmt.Sprintf("%05s", filenameOnly) + fileSuffix
return bucket.PutObject(objectPathName+fileName, fc)
}
func uploadPacked(bucket *oss.Bucket, filename, contentHash,
objectPath string, word float64) error {
type packed struct {
FileName string `json:"fileName"`
Hash string `json:"hash"`
ImagesName []string `json:"imagesName"`
OssImagesPath string `json:"ossImagesPath"`
}
p := packed{
FileName: filename,
Hash: contentHash,
OssImagesPath: objectPath + "images/",
}
for i := 1; i <= int(word); i++ {
p.ImagesName = append(p.ImagesName, fmt.Sprintf("%05d", i)+".png")
}
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.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 fileContentHash(file io.Reader) (string, []byte) {
b, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println(err)
}
hash := md5.New()
io.WriteString(hash, string(b))
result := hash.Sum(nil)
return fmt.Sprintf("%s", hex.EncodeToString(result)), b
}
func downloadFile(url 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)
fmt.Println(url)
if err != nil {
return err
}
//读取服务器返回的文件大小
fsize, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 32)
if err != nil {
fmt.Println(err)
}
//创建文件
var filenameWithSuffix string
filenameWithSuffix = path.Base(url) //获取文件名带后缀
var fileSuffix string
fileSuffix = path.Ext(filenameWithSuffix) //获取文件后缀
var filenameOnly string
filenameOnly = strings.Replace(filenameWithSuffix, fileSuffix, ".zip", -1) //获取文件名
file, err := os.Create("/data/files/" + filenameOnly)
if err != nil {
return err
}
defer file.Close()
if resp.Body == nil {
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