设计用户代理,实现
DealWithRequests()
中的几种简单逻辑指令,如文件列表获取、文件拷贝、Fork操作等。
命令转发
- 在 顶点云(应用)服务器逻辑实现 中,在校验用户身份后,客户端发送的指令会被转发给
rc.DealWithRequests()
方法执行,其中rc
是用户对象。 - 该方法是用户结构处理消息的入口,在函数头部先将用户的云盘信息、头像链接等发送给客户端,之后进入循环,等待客户端的指令,并依据指令的标识符转发:
1 | func (u *cuser) DealWithRequests(db *sql.DB) { |
- 下面以文件列表作为例子,简述如何处理基本的逻辑。
文件列表获取
- 要实现的系统规模不大,因此没有针对 Golang 编写 ORM,也没有使用现成的库,直接构造了 SQL 语句查找,因此看起来代码较复杂、凌乱。
- 用户要获取某个目录下的文件列表,需要将查询路径包含在指令中发送,因此将列表获取的指令定义为
ls<SEP>是否递归查询<SEP>查询路径<SEP>搜索参数
。ls
方法根据指令参数决定是否递归遍历目录、是否按关键词检索。关键词数量可变。 - 检索当前目录下文件时,构建的 SQL 语句为
path = 目录
,递归检索时,SQL 为path like '目录%'
。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99func (u *cuser) ls(db *sql.DB, command string) {
// 指令格式:LS<SEP>是否递归查询<SEP>查询路径<SEP>搜索参数
var queryString string
var returnString string = fmt.Sprintf(`UID%sPATH%sFILE%sCREATED TIME%sSIZE
%sSHARED%sMODE`, conf.SEPERATER, conf.SEPERATER, conf.SEPERATER,
conf.SEPERATER, conf.SEPERATER, conf.SEPERATER)
var uid, ownerid, cfileid, shared, downloaded, cuid, csize, cref int
var private, isdir bool
var path, perlink, filename, linkpass, created, cmd5, ccreated string
var err error
var ufilelist *sql.Rows
var recurssive int
// 验证指令格式是否合法
args := generateArgs(command, 0)
valid := true
argAll := "%"
if args == nil || len(args) < 3 ||
strings.ToUpper(args[0]) != "LS" ||
!isPathFormatValid(args[2]) {
valid = false
goto LS_VERIFY
}
recurssive, err = strconv.Atoi(args[1])
if err != nil || recurssive != 0 && recurssive != 1 {
valid = false
goto LS_VERIFY
}
for i := 3; i < len(args); i++ {
if args[i] != "" {
argAll += (args[i] + "%")
}
}
// 调整当前用户所在的目录
u.curpath = args[2]
// 根据参数决定是否递归搜索
if recurssive == 0 {
queryString = fmt.Sprintf(`select uid, ownerid, cfileid, path, perlink,
created, shared, downloaded, filename, private, linkpass, isdir
from ufile where ownerid=%d and path='%s' and filename like '%s'`,
u.id, u.curpath, argAll)
} else {
queryString = fmt.Sprintf(`select uid, ownerid, cfileid, path, perlink,
created, shared, downloaded, filename, private, linkpass, isdir
from ufile where ownerid=%d and path like '%s%%' and filename
like '%s'`, u.id, u.curpath, argAll)
}
ufilelist, err = db.Query(queryString)
if err != nil {
valid = false
goto LS_VERIFY
}
// 将资源列表中的资源信息依次格式化为字符串
for ufilelist.Next() {
err = ufilelist.Scan(&uid, &ownerid, &cfileid, &path, &perlink, &created,
&shared, &downloaded, &filename, &private, &linkpass, &isdir)
if err != nil {
valid = false
break
}
// 若引用实体文件则获取实体文件大小
if cfileid >= 0 {
tcfile := db.QueryRow(fmt.Sprintf(`SELECT uid, md5, size, ref,
created FROM cfile where uid='%d'`, cfileid))
if tcfile == nil {
continue
}
err = tcfile.Scan(&cuid, &cmd5, &csize, &cref, &ccreated)
if err != nil {
continue
}
} else {
csize = 0
}
// 添加格式化信息
returnString += fmt.Sprintf("\n%d%s%s%s%s%s%s%s%d%s%d%s", uid,
conf.SEPERATER, path, conf.SEPERATER, filename, conf.SEPERATER,
created, conf.SEPERATER, csize, conf.SEPERATER, shared, conf.SEPERATER)
// 根据是否为目录添加类型后缀
if isdir {
returnString += "DIR"
} else {
returnString += "FILE"
}
}
LS_VERIFY:
if !valid {
// 请求失败时返回错误信息
u.listen.SendBytes([]byte("error happens when querying files"))
return
}
// 请求成功返回格式化的信息
u.listen.SendBytes([]byte(returnString))
}
专栏目录:顶点云(应用)设计与实现
此专栏的上一篇文章:顶点云(应用)服务器逻辑实现
此专栏的下一篇文章:顶点云(应用)用户文件传输代理
原创作品,允许转载,转载时无需告知,但请务必以超链接形式标明文章原始出处(http://blog.forec.cn/2016/12/03/zenith-cloud-7/) 、作者信息(Forec)和本声明。