mirror of
https://github.com/crawlab-team/crawlab.git
synced 2026-01-27 17:50:53 +01:00
Revert "Revert "V0.4.0 imporve error response""
This reverts commit 9744f45e86.
This commit is contained in:
100
backend/services/context/context.go
Normal file
100
backend/services/context/context.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"crawlab/constants"
|
||||
"crawlab/errors"
|
||||
"crawlab/model"
|
||||
"fmt"
|
||||
"github.com/apex/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
errors2 "github.com/pkg/errors"
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
*gin.Context
|
||||
}
|
||||
|
||||
func (c *Context) User() *model.User {
|
||||
userIfe, exists := c.Get(constants.ContextUser)
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
user, ok := userIfe.(*model.User)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return user
|
||||
}
|
||||
func (c *Context) Success(data interface{}, metas ...interface{}) {
|
||||
var meta interface{}
|
||||
if len(metas) == 0 {
|
||||
meta = gin.H{}
|
||||
} else {
|
||||
meta = metas[0]
|
||||
}
|
||||
if data == nil {
|
||||
data = gin.H{}
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": "ok",
|
||||
"message": "success",
|
||||
"data": data,
|
||||
"meta": meta,
|
||||
"error": "",
|
||||
})
|
||||
}
|
||||
func (c *Context) Failed(err error, variables ...interface{}) {
|
||||
c.failed(err, http.StatusOK, variables...)
|
||||
}
|
||||
func (c *Context) failed(err error, httpCode int, variables ...interface{}) {
|
||||
errStr := err.Error()
|
||||
if len(variables) > 0 {
|
||||
errStr = fmt.Sprintf(errStr, variables...)
|
||||
}
|
||||
log.Errorf("handle error:" + errStr)
|
||||
debug.PrintStack()
|
||||
causeError := errors2.Cause(err)
|
||||
switch causeError.(type) {
|
||||
case errors.OPError:
|
||||
opError := causeError.(errors.OPError)
|
||||
|
||||
c.AbortWithStatusJSON(opError.HttpCode, gin.H{
|
||||
"status": "ok",
|
||||
"message": "error",
|
||||
"error": errStr,
|
||||
})
|
||||
break
|
||||
case validator.ValidationErrors:
|
||||
validatorErrors := causeError.(validator.ValidationErrors)
|
||||
//firstError := validatorErrors[0].(validator.FieldError)
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
|
||||
"status": "ok",
|
||||
"message": "error",
|
||||
"error": validatorErrors.Error(),
|
||||
})
|
||||
break
|
||||
default:
|
||||
fmt.Println("deprecated....")
|
||||
c.AbortWithStatusJSON(httpCode, gin.H{
|
||||
"status": "ok",
|
||||
"message": "error",
|
||||
"error": errStr,
|
||||
})
|
||||
}
|
||||
}
|
||||
func (c *Context) FailedWithError(err error, httpCode ...int) {
|
||||
|
||||
var code = 200
|
||||
if len(httpCode) > 0 {
|
||||
code = httpCode[0]
|
||||
}
|
||||
c.failed(err, code)
|
||||
|
||||
}
|
||||
|
||||
func WithGinContext(context *gin.Context) *Context {
|
||||
return &Context{Context: context}
|
||||
}
|
||||
@@ -3,11 +3,15 @@ package services
|
||||
import (
|
||||
"crawlab/constants"
|
||||
"crawlab/database"
|
||||
"crawlab/lib/cron"
|
||||
"crawlab/model"
|
||||
"crawlab/utils"
|
||||
"encoding/json"
|
||||
"github.com/apex/log"
|
||||
"github.com/spf13/viper"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
@@ -16,13 +20,38 @@ var TaskLogChanMap = utils.NewChanMap()
|
||||
|
||||
// 获取本地日志
|
||||
func GetLocalLog(logPath string) (fileBytes []byte, err error) {
|
||||
fileBytes, err = ioutil.ReadFile(logPath)
|
||||
|
||||
f, err := os.Open(logPath)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
log.Error(err.Error())
|
||||
debug.PrintStack()
|
||||
return fileBytes, err
|
||||
return nil, err
|
||||
}
|
||||
return fileBytes, nil
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
debug.PrintStack()
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
const bufLen = 2 * 1024 * 1024
|
||||
logBuf := make([]byte, bufLen)
|
||||
|
||||
off := int64(0)
|
||||
if fi.Size() > int64(len(logBuf)) {
|
||||
off = fi.Size() - int64(len(logBuf))
|
||||
}
|
||||
n, err := f.ReadAt(logBuf, off)
|
||||
|
||||
//到文件结尾会有EOF标识
|
||||
if err != nil && err.Error() != "EOF" {
|
||||
log.Error(err.Error())
|
||||
debug.PrintStack()
|
||||
return nil, err
|
||||
}
|
||||
logBuf = logBuf[:n]
|
||||
return logBuf, nil
|
||||
}
|
||||
|
||||
// 获取远端日志
|
||||
@@ -42,7 +71,7 @@ func GetRemoteLog(task model.Task) (logStr string, err error) {
|
||||
|
||||
// 发布获取日志消息
|
||||
channel := "nodes:" + task.NodeId.Hex()
|
||||
if err := database.Publish(channel, string(msgBytes)); err != nil {
|
||||
if _, err := database.RedisClient.Publish(channel, string(msgBytes)); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return "", err
|
||||
}
|
||||
@@ -55,3 +84,36 @@ func GetRemoteLog(task model.Task) (logStr string, err error) {
|
||||
|
||||
return logStr, nil
|
||||
}
|
||||
|
||||
func DeleteLogPeriodically() {
|
||||
logDir := viper.GetString("log.path")
|
||||
if !utils.Exists(logDir) {
|
||||
log.Error("Can Not Set Delete Logs Periodically,No Log Dir")
|
||||
return
|
||||
}
|
||||
rd, err := ioutil.ReadDir(logDir)
|
||||
if err != nil {
|
||||
log.Error("Read Log Dir Failed")
|
||||
return
|
||||
}
|
||||
|
||||
for _, fi := range rd {
|
||||
if fi.IsDir() {
|
||||
log.Info(filepath.Join(logDir, fi.Name()))
|
||||
os.RemoveAll(filepath.Join(logDir, fi.Name()))
|
||||
log.Info("Delete Log File Success")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func InitDeleteLogPeriodically() error {
|
||||
c := cron.New(cron.WithSeconds())
|
||||
if _, err := c.AddFunc(viper.GetString("log.deleteFrequency"), DeleteLogPeriodically); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Start()
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
50
backend/services/log_test.go
Normal file
50
backend/services/log_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"crawlab/config"
|
||||
"fmt"
|
||||
"github.com/apex/log"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/spf13/viper"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeleteLogPeriodically(t *testing.T) {
|
||||
Convey("Test DeleteLogPeriodically", t, func() {
|
||||
if err := config.InitConfig("../conf/config.yml"); err != nil {
|
||||
log.Error("init config error:" + err.Error())
|
||||
panic(err)
|
||||
}
|
||||
log.Info("初始化配置成功")
|
||||
logDir := viper.GetString("log.path")
|
||||
log.Info(logDir)
|
||||
DeleteLogPeriodically()
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetLocalLog(t *testing.T) {
|
||||
//create a log file for test
|
||||
logPath := "../logs/crawlab/test.log"
|
||||
f, err := os.Create(logPath)
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
|
||||
} else {
|
||||
_, err = f.Write([]byte("This is for test"))
|
||||
}
|
||||
|
||||
Convey("Test GetLocalLog", t, func() {
|
||||
Convey("Test response", func() {
|
||||
logStr, err := GetLocalLog(logPath)
|
||||
log.Info(string(logStr))
|
||||
fmt.Println(err)
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
})
|
||||
})
|
||||
//delete the test log file
|
||||
os.Remove(logPath)
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crawlab/constants"
|
||||
"crawlab/database"
|
||||
"crawlab/lib/cron"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/apex/log"
|
||||
"github.com/globalsign/mgo/bson"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"github.com/spf13/viper"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
@@ -73,23 +75,11 @@ func GetCurrentNode() (model.Node, error) {
|
||||
if err != nil {
|
||||
// 如果为主节点,表示为第一次注册,插入节点信息
|
||||
if IsMaster() {
|
||||
// 获取本机IP地址
|
||||
ip, err := register.GetRegister().GetIp()
|
||||
// 获取本机信息
|
||||
ip, mac, key, err := model.GetNodeBaseInfo()
|
||||
if err != nil {
|
||||
debug.PrintStack()
|
||||
return model.Node{}, err
|
||||
}
|
||||
|
||||
mac, err := register.GetRegister().GetMac()
|
||||
if err != nil {
|
||||
debug.PrintStack()
|
||||
return model.Node{}, err
|
||||
}
|
||||
|
||||
key, err := register.GetRegister().GetKey()
|
||||
if err != nil {
|
||||
debug.PrintStack()
|
||||
return model.Node{}, err
|
||||
return node, err
|
||||
}
|
||||
|
||||
// 生成节点
|
||||
@@ -97,7 +87,7 @@ func GetCurrentNode() (model.Node, error) {
|
||||
Key: key,
|
||||
Id: bson.NewObjectId(),
|
||||
Ip: ip,
|
||||
Name: key,
|
||||
Name: ip,
|
||||
Mac: mac,
|
||||
IsMaster: true,
|
||||
}
|
||||
@@ -124,6 +114,7 @@ func IsMaster() bool {
|
||||
return viper.GetString("server.master") == Yes
|
||||
}
|
||||
|
||||
// 所有调用IsMasterNode的方法,都永远会在master节点执行,所以GetCurrentNode方法返回永远是master节点
|
||||
// 该ID的节点是否为主节点
|
||||
func IsMasterNode(id string) bool {
|
||||
curNode, _ := GetCurrentNode()
|
||||
@@ -176,72 +167,54 @@ func UpdateNodeStatus() {
|
||||
// 在Redis中删除该节点
|
||||
if err := database.RedisClient.HDel("nodes", data.Key); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 在MongoDB中该节点设置状态为离线
|
||||
s, c := database.GetCol("nodes")
|
||||
defer s.Close()
|
||||
var node model.Node
|
||||
if err := c.Find(bson.M{"key": key}).One(&node); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
}
|
||||
node.Status = constants.StatusOffline
|
||||
if err := node.Save(); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 更新节点信息到数据库
|
||||
s, c := database.GetCol("nodes")
|
||||
defer s.Close()
|
||||
var node model.Node
|
||||
if err := c.Find(bson.M{"key": key}).One(&node); err != nil {
|
||||
// 数据库不存在该节点
|
||||
node = model.Node{
|
||||
Key: key,
|
||||
Name: key,
|
||||
Ip: data.Ip,
|
||||
Port: "8000",
|
||||
Mac: data.Mac,
|
||||
Status: constants.StatusOnline,
|
||||
IsMaster: data.Master,
|
||||
}
|
||||
if err := node.Add(); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 数据库存在该节点
|
||||
node.Status = constants.StatusOnline
|
||||
if err := node.Save(); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
// 处理node信息
|
||||
handleNodeInfo(key, data)
|
||||
}
|
||||
|
||||
// 重置不在redis的key为offline
|
||||
model.ResetNodeStatusToOffline(list)
|
||||
}
|
||||
|
||||
func handleNodeInfo(key string, data Data) {
|
||||
// 更新节点信息到数据库
|
||||
s, c := database.GetCol("nodes")
|
||||
defer s.Close()
|
||||
|
||||
// 同个key可能因为并发,被注册多次
|
||||
var nodes []model.Node
|
||||
_ = c.Find(bson.M{"key": key}).All(&nodes)
|
||||
if nodes != nil && len(nodes) > 1 {
|
||||
for _, node := range nodes {
|
||||
_ = c.RemoveId(node.Id)
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历数据库中的节点列表
|
||||
nodes, err := model.GetNodeList(nil)
|
||||
for _, node := range nodes {
|
||||
hasNode := false
|
||||
for _, key := range list {
|
||||
if key == node.Key {
|
||||
hasNode = true
|
||||
break
|
||||
}
|
||||
var node model.Node
|
||||
if err := c.Find(bson.M{"key": key}).One(&node); err != nil {
|
||||
// 数据库不存在该节点
|
||||
node = model.Node{
|
||||
Key: key,
|
||||
Name: data.Ip,
|
||||
Ip: data.Ip,
|
||||
Port: "8000",
|
||||
Mac: data.Mac,
|
||||
Status: constants.StatusOnline,
|
||||
IsMaster: data.Master,
|
||||
}
|
||||
if !hasNode {
|
||||
node.Status = constants.StatusOffline
|
||||
if err := node.Save(); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
continue
|
||||
if err := node.Add(); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 数据库存在该节点
|
||||
node.Status = constants.StatusOnline
|
||||
if err := node.Save(); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,13 +260,12 @@ func UpdateNodeData() {
|
||||
}
|
||||
}
|
||||
|
||||
func MasterNodeCallback(channel string, msgStr string) {
|
||||
func MasterNodeCallback(message redis.Message) (err error) {
|
||||
// 反序列化
|
||||
var msg NodeMessage
|
||||
if err := json.Unmarshal([]byte(msgStr), &msg); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
if err := json.Unmarshal(message.Data, &msg); err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if msg.Type == constants.MsgTypeGetLog {
|
||||
@@ -310,16 +282,15 @@ func MasterNodeCallback(channel string, msgStr string) {
|
||||
sysInfoBytes, _ := json.Marshal(&msg.SysInfo)
|
||||
ch <- string(sysInfoBytes)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WorkerNodeCallback(channel string, msgStr string) {
|
||||
func WorkerNodeCallback(message redis.Message) (err error) {
|
||||
// 反序列化
|
||||
msg := NodeMessage{}
|
||||
fmt.Println(msgStr)
|
||||
if err := json.Unmarshal([]byte(msgStr), &msg); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
if err := json.Unmarshal(message.Data, &msg); err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if msg.Type == constants.MsgTypeGetLog {
|
||||
@@ -333,26 +304,27 @@ func WorkerNodeCallback(channel string, msgStr string) {
|
||||
|
||||
// 获取本地日志
|
||||
logStr, err := GetLocalLog(msg.LogPath)
|
||||
log.Info(string(logStr))
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
msgSd.Error = err.Error()
|
||||
msgSd.Log = err.Error()
|
||||
} else {
|
||||
msgSd.Log = string(logStr)
|
||||
}
|
||||
msgSd.Log = string(logStr)
|
||||
|
||||
// 序列化
|
||||
msgSdBytes, err := json.Marshal(&msgSd)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// 发布消息给主节点
|
||||
fmt.Println(msgSd)
|
||||
if err := database.Publish("nodes:master", string(msgSdBytes)); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
log.Info("publish get log msg to master")
|
||||
if _, err := database.RedisClient.Publish("nodes:master", string(msgSdBytes)); err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
} else if msg.Type == constants.MsgTypeCancelTask {
|
||||
// 取消任务
|
||||
@@ -362,8 +334,7 @@ func WorkerNodeCallback(channel string, msgStr string) {
|
||||
// 获取环境信息
|
||||
sysInfo, err := GetLocalSystemInfo()
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
return err
|
||||
}
|
||||
msgSd := NodeMessage{
|
||||
Type: constants.MsgTypeGetSystemInfo,
|
||||
@@ -374,14 +345,14 @@ func WorkerNodeCallback(channel string, msgStr string) {
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
return err
|
||||
}
|
||||
fmt.Println(msgSd)
|
||||
if err := database.Publish("nodes:master", string(msgSdBytes)); err != nil {
|
||||
if _, err := database.RedisClient.Publish("nodes:master", string(msgSdBytes)); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return
|
||||
return err
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 初始化节点服务
|
||||
@@ -399,25 +370,27 @@ func InitNodeService() error {
|
||||
// 首次更新节点数据(注册到Redis)
|
||||
UpdateNodeData()
|
||||
|
||||
// 消息订阅
|
||||
var sub database.Subscriber
|
||||
sub.Connect()
|
||||
|
||||
// 获取当前节点
|
||||
node, err := GetCurrentNode()
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
if IsMaster() {
|
||||
// 如果为主节点,订阅主节点通信频道
|
||||
channel := "nodes:master"
|
||||
sub.Subscribe(channel, MasterNodeCallback)
|
||||
err := database.RedisClient.Subscribe(ctx, MasterNodeCallback, channel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 若为工作节点,订阅单独指定通信频道
|
||||
channel := "nodes:" + node.Id.Hex()
|
||||
sub.Subscribe(channel, WorkerNodeCallback)
|
||||
err := database.RedisClient.Subscribe(ctx, WorkerNodeCallback, channel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 如果为主节点,每30秒刷新所有节点信息
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crawlab/constants"
|
||||
"crawlab/database"
|
||||
"crawlab/lib/cron"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"github.com/apex/log"
|
||||
"github.com/globalsign/mgo"
|
||||
"github.com/globalsign/mgo/bson"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/satori/go.uuid"
|
||||
"github.com/spf13/viper"
|
||||
@@ -20,6 +22,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type SpiderFileData struct {
|
||||
@@ -30,6 +33,7 @@ type SpiderFileData struct {
|
||||
type SpiderUploadMessage struct {
|
||||
FileId string
|
||||
FileName string
|
||||
SpiderId string
|
||||
}
|
||||
|
||||
// 从项目目录中获取爬虫列表
|
||||
@@ -39,7 +43,9 @@ func GetSpidersFromDir() ([]model.Spider, error) {
|
||||
|
||||
// 如果爬虫项目目录不存在,则创建一个
|
||||
if !utils.Exists(srcPath) {
|
||||
if err := os.MkdirAll(srcPath, 0666); err != nil {
|
||||
mask := syscall.Umask(0) // 改为 0000 八进制
|
||||
defer syscall.Umask(mask) // 改为原来的 umask
|
||||
if err := os.MkdirAll(srcPath, 0766); err != nil {
|
||||
debug.PrintStack()
|
||||
return []model.Spider{}, err
|
||||
}
|
||||
@@ -85,16 +91,25 @@ func GetSpidersFromDir() ([]model.Spider, error) {
|
||||
|
||||
// 将爬虫保存到数据库
|
||||
func SaveSpiders(spiders []model.Spider) error {
|
||||
// 遍历爬虫列表
|
||||
s, c := database.GetCol("spiders")
|
||||
defer s.Close()
|
||||
|
||||
if len(spiders) == 0 {
|
||||
err := model.RemoveAllSpider()
|
||||
if err != nil {
|
||||
log.Error("remove all spider error:" + err.Error())
|
||||
return err
|
||||
}
|
||||
log.Info("get spider from dir is empty,removed all spider")
|
||||
return nil
|
||||
}
|
||||
// 如果该爬虫不存在于数据库,则保存爬虫到数据库
|
||||
for _, spider := range spiders {
|
||||
// 忽略非自定义爬虫
|
||||
if spider.Type != constants.Customized {
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果该爬虫不存在于数据库,则保存爬虫到数据库
|
||||
s, c := database.GetCol("spiders")
|
||||
defer s.Close()
|
||||
var spider_ *model.Spider
|
||||
if err := c.Find(bson.M{"src": spider.Src}).One(&spider_); err != nil {
|
||||
// 不存在
|
||||
@@ -102,11 +117,8 @@ func SaveSpiders(spiders []model.Spider) error {
|
||||
debug.PrintStack()
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 存在
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -131,15 +143,14 @@ func ZipSpider(spider model.Spider) (filePath string, err error) {
|
||||
// 如果源文件夹不存在,抛错
|
||||
if !utils.Exists(spider.Src) {
|
||||
debug.PrintStack()
|
||||
// 删除该爬虫,否则会一直报错
|
||||
_ = model.RemoveSpider(spider.Id)
|
||||
return "", errors.New("source path does not exist")
|
||||
}
|
||||
|
||||
// 临时文件路径
|
||||
randomId := uuid.NewV4()
|
||||
if err != nil {
|
||||
debug.PrintStack()
|
||||
return "", err
|
||||
}
|
||||
|
||||
filePath = filepath.Join(
|
||||
viper.GetString("other.tmppath"),
|
||||
randomId.String()+".zip",
|
||||
@@ -171,6 +182,7 @@ func UploadToGridFs(spider model.Spider, fileName string, filePath string) (fid
|
||||
// 如果存在FileId删除GridFS上的老文件
|
||||
if !utils.IsObjectIdNull(spider.FileId) {
|
||||
if err = gf.RemoveId(spider.FileId); err != nil {
|
||||
log.Error("remove gf file:" + err.Error())
|
||||
debug.PrintStack()
|
||||
}
|
||||
}
|
||||
@@ -223,7 +235,7 @@ func ReadFileByStep(filePath string, handle func([]byte, *mgo.GridFile), fileCre
|
||||
for {
|
||||
switch nr, err := f.Read(s[:]); true {
|
||||
case nr < 0:
|
||||
fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
|
||||
_, _ = fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
|
||||
debug.PrintStack()
|
||||
case nr == 0: // EOF
|
||||
return nil
|
||||
@@ -231,7 +243,6 @@ func ReadFileByStep(filePath string, handle func([]byte, *mgo.GridFile), fileCre
|
||||
handle(s[0:nr], fileCreate)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 发布所有爬虫
|
||||
@@ -247,8 +258,8 @@ func PublishAllSpiders() error {
|
||||
for _, spider := range spiders {
|
||||
// 发布爬虫
|
||||
if err := PublishSpider(spider); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return err
|
||||
log.Errorf("publish spider error:" + err.Error())
|
||||
// return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,13 +300,14 @@ func PublishSpider(spider model.Spider) (err error) {
|
||||
msg := SpiderUploadMessage{
|
||||
FileId: fid.Hex(),
|
||||
FileName: fileName,
|
||||
SpiderId: spider.Id.Hex(),
|
||||
}
|
||||
msgStr, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
channel := "files:upload"
|
||||
if err = database.Publish(channel, string(msgStr)); err != nil {
|
||||
if _, err = database.RedisClient.Publish(channel, string(msgStr)); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
@@ -305,24 +317,24 @@ func PublishSpider(spider model.Spider) (err error) {
|
||||
}
|
||||
|
||||
// 上传爬虫回调
|
||||
func OnFileUpload(channel string, msgStr string) {
|
||||
func OnFileUpload(message redis.Message) (err error) {
|
||||
s, gf := database.GetGridFs("files")
|
||||
defer s.Close()
|
||||
|
||||
// 反序列化消息
|
||||
var msg SpiderUploadMessage
|
||||
if err := json.Unmarshal([]byte(msgStr), &msg); err != nil {
|
||||
if err := json.Unmarshal(message.Data, &msg); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// 从GridFS获取该文件
|
||||
f, err := gf.OpenId(bson.ObjectIdHex(msg.FileId))
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
log.Errorf("open file id: " + msg.FileId + ", spider id:" + msg.SpiderId + ", error: " + err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
@@ -335,7 +347,7 @@ func OnFileUpload(channel string, msgStr string) {
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
return err
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
|
||||
@@ -343,33 +355,34 @@ func OnFileUpload(channel string, msgStr string) {
|
||||
if _, err := io.Copy(tmpFile, f); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// 解压缩临时文件到目标文件夹
|
||||
dstPath := filepath.Join(
|
||||
viper.GetString("spider.path"),
|
||||
//strings.Replace(msg.FileName, ".zip", "", -1),
|
||||
// strings.Replace(msg.FileName, ".zip", "", -1),
|
||||
)
|
||||
if err := utils.DeCompress(tmpFile, dstPath); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// 关闭临时文件
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除临时文件
|
||||
if err := os.Remove(tmpFilePath); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 启动爬虫服务
|
||||
@@ -394,9 +407,11 @@ func InitSpiderService() error {
|
||||
|
||||
// 订阅文件上传
|
||||
channel := "files:upload"
|
||||
var sub database.Subscriber
|
||||
sub.Connect()
|
||||
sub.Subscribe(channel, OnFileUpload)
|
||||
|
||||
//sub.Connect()
|
||||
ctx := context.Background()
|
||||
return database.RedisClient.Subscribe(ctx, OnFileUpload, channel)
|
||||
|
||||
}
|
||||
|
||||
// 启动定时任务
|
||||
|
||||
@@ -112,7 +112,7 @@ func GetRemoteSystemInfo(id string) (sysInfo model.SystemInfo, err error) {
|
||||
|
||||
// 序列化
|
||||
msgBytes, _ := json.Marshal(&msg)
|
||||
if err := database.Publish("nodes:"+id, string(msgBytes)); err != nil {
|
||||
if _, err := database.RedisClient.Publish("nodes:"+id, string(msgBytes)); err != nil {
|
||||
return model.SystemInfo{}, err
|
||||
}
|
||||
|
||||
|
||||
@@ -408,9 +408,12 @@ func GetTaskLog(id string) (logStr string, err error) {
|
||||
logStr = string(logBytes)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return "", err
|
||||
logStr = string(err.Error())
|
||||
// return "", err
|
||||
} else {
|
||||
logStr = string(logBytes)
|
||||
}
|
||||
logStr = string(logBytes)
|
||||
|
||||
} else {
|
||||
// 若不为主节点,获取远端日志
|
||||
logStr, err = GetRemoteLog(task)
|
||||
@@ -463,7 +466,7 @@ func CancelTask(id string) (err error) {
|
||||
}
|
||||
|
||||
// 发布消息
|
||||
if err := database.Publish("nodes:"+task.NodeId.Hex(), string(msgBytes)); err != nil {
|
||||
if _, err := database.RedisClient.Publish("nodes:"+task.NodeId.Hex(), string(msgBytes)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -472,6 +475,7 @@ func CancelTask(id string) (err error) {
|
||||
}
|
||||
|
||||
func HandleTaskError(t model.Task, err error) {
|
||||
log.Error("handle task error:" + err.Error())
|
||||
t.Status = constants.StatusError
|
||||
t.Error = err.Error()
|
||||
t.FinishTs = time.Now()
|
||||
|
||||
@@ -5,11 +5,9 @@ import (
|
||||
"crawlab/model"
|
||||
"crawlab/utils"
|
||||
"errors"
|
||||
"github.com/apex/log"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/globalsign/mgo/bson"
|
||||
"github.com/spf13/viper"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -24,28 +22,38 @@ func InitUserService() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetToken(username string) (tokenStr string, err error) {
|
||||
user, err := model.GetUserByUsername(username)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
debug.PrintStack()
|
||||
return
|
||||
}
|
||||
|
||||
func MakeToken(user *model.User) (tokenStr string, err error) {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"id": user.Id,
|
||||
"username": user.Username,
|
||||
"nbf": time.Now().Unix(),
|
||||
})
|
||||
|
||||
tokenStr, err = token.SignedString([]byte(viper.GetString("server.secret")))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
return token.SignedString([]byte(viper.GetString("server.secret")))
|
||||
|
||||
}
|
||||
|
||||
//func GetToken(username string) (tokenStr string, err error) {
|
||||
// user, err := model.GetUserByUsername(username)
|
||||
// if err != nil {
|
||||
// log.Errorf(err.Error())
|
||||
// debug.PrintStack()
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
// "id": user.Id,
|
||||
// "username": user.Username,
|
||||
// "nbf": time.Now().Unix(),
|
||||
// })
|
||||
//
|
||||
// tokenStr, err = token.SignedString([]byte(viper.GetString("server.secret")))
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// return
|
||||
//}
|
||||
|
||||
func SecretFunc() jwt.Keyfunc {
|
||||
return func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(viper.GetString("server.secret")), nil
|
||||
|
||||
Reference in New Issue
Block a user