memfire实现gitbook文章阅读量插件

背景

个人开发者普遍拥有属于自己的个人博客站点。常见的框架无论是Hexo、Gitbook,亦或是Docsify,这些框架本身并不支持文章阅读量或者站点访问量的功能,需要各种对应的插件支持。

目前市面上这些插件基本上是基于busuanzi,LeanCloud实现的,而Memfire旨在提供数据库服务,若后续提供sdk功能,能够实现对应框架的插件供个人开发者使用,并提供相关文章,也能吸引很多个人开发者。(因为我本身也是基于使用插件的需要,才在LeanCloud上注册了账户。)

Memfire官方地址

概述

基本上述背景,尝试着基于memfire去实现一个统计gitbook文章访问量的插件。

实现

建库建表

登录memfiredb

需要在memfiredb.com上注册账户,并创建自己的数据库
1

进入在线编辑器

点击SQL查询进入在线编辑器
2

建表

1
2
3
4
5
6
7
CREATE TABLE counter (
id serial NOT NULL,
url varchar(500),
time int,
title varchar(200),
PRIMARY KEY (id)
)

3

数据库连接

因为目前memfire还不提供sdk等功能,所以先自己简单写一个中间服务,便于插件访问。

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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package main

import (
"database/sql"
"fmt"
"log"
"net/http"

"github.com/gin-gonic/gin"
_ "github.com/lib/pq"
)

const (
host = "47.102.41.197"
port = 5433
user = "new"
password = "123456"
dbname = "db89549e379d4f423fa26c5e52422a50a1tianwei123"
)

func main() {
r := gin.Default()
r.Use(Cors()) //开启中间件 允许使用跨域请求
r.GET("/counter", GetCount) // 获取文章访问量
r.POST("/counter", AddCount) // 创建文章访问量
r.PUT("/counter", UpdateCount) // 更新文章访问量
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin") //请求头部
if origin != "" {
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
c.Header("Access-Control-Max-Age", "172800")
c.Header("Access-Control-Allow-Credentials", "true")
}

//允许类型校验
if method == "OPTIONS" {
c.JSON(http.StatusOK, "ok!")
}
defer func() {
if err := recover(); err != nil {
log.Printf("Panic info is: %v", err)
}
}()
c.Next()
}
}

func GetCount(c *gin.Context) {
url := c.Query("url")
if url == "" {
url = "#"
}

psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}
rows, err := db.Query("SELECT time FROM counter WHERE url = $1", url)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var time int
for rows.Next() {
err := rows.Scan(&time)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Row[%d]\n", time)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}

defer db.Close()
c.JSON(200, gin.H{
"time":time,
})
return
}

func AddCount(c *gin.Context) {
url := c.PostForm("url")
if url == "" {
url = "#"
}

psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}

insert := "INSERT INTO counter(url, time) VALUES ("
insert += "'" + url + "', 1)"
fmt.Println("insert statement: ", insert)

if _, err := db.Exec(insert); err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted data: %s\n", insert)
defer db.Close()
return
}

func UpdateCount(c *gin.Context) {
url := c.PostForm("url")
if url == "" {
url = "#"
}
time := c.PostForm("time")
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}
update := "UPDATE counter SET time=" + time + " Where url= '" + url + "'"
if _, err := db.Exec(update); err != nil {
log.Fatal(err)
}
fmt.Printf("update data: %s\n", update)
defer db.Close()
return
}

构建gitbook插件

仿造其他插件,建立代码仓库
4

修改book下plugin.js

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
 var gitbook = window.gitbook;

/*
<!-- Start of CuterCounter Code -->
<a href="http://www.cutercounter.com/" target="_blank"><img src="http://www.cutercounter.com/hit.php?id=gmvufxqck&nd=1&style=116" border="0" alt="visitor counter"></a>
<!-- End of CuterCounter Code -->
*/

var iconSVg = '<svg t="1543310294340" \
class="icon" style="" viewBox="0 0 1024 1024" version="1.1" \
xmlns="http://www.w3.org/2000/svg" p-id="1104" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14"><defs><style type="text/css"></style></defs>\
<path d="M512 416a96 96 0 1 0 0 192 96 96 0 0 0 0-192z m511.952 102.064c-0.016-0.448-0.064-0.864-0.096-1.296a8.16 8.16 0 0 0-0.08-0.656c0-0.32-0.064-0.624-0.128-0.928-0.032-0.368-0.064-0.736-0.128-1.088-0.032-0.048-0.032-0.096-0.032-0.144a39.488 39.488 0 0 0-10.704-21.536c-32.672-39.616-71.536-74.88-111.04-107.072-85.088-69.392-182.432-127.424-289.856-150.8-62.112-13.504-124.576-14.064-187.008-2.64-56.784 10.384-111.504 32-162.72 58.784-80.176 41.92-153.392 99.696-217.184 164.48-11.808 11.984-23.552 24.224-34.288 37.248-14.288 17.328-14.288 37.872 0 55.216 32.672 39.616 71.52 74.848 111.04 107.056 85.12 69.392 182.448 127.408 289.888 150.784 62.096 13.504 124.608 14.096 187.008 2.656 56.768-10.4 111.488-32 162.736-58.768 80.176-41.936 153.376-99.696 217.184-164.48 11.792-12 23.536-24.224 34.288-37.248 5.712-5.872 9.456-13.44 10.704-21.568l0.032-0.128a12.592 12.592 0 0 0 0.128-1.088c0.064-0.304 0.096-0.624 0.128-0.928l0.08-0.656 0.096-1.28c0.032-0.656 0.048-1.296 0.048-1.952l-0.096-1.968zM512 704c-106.032 0-192-85.952-192-192s85.952-192 192-192 192 85.968 192 192c0 106.048-85.968 192-192 192z"\
fill="#CCC" p-id="1105"></path></svg>'

require(["gitbook", "jQuery"], function (gitbook, $) {
gitbook.events.bind("page.change", function() {
var bookHeader = $('.book-header')
var lastChild = bookHeader.children().last()

var renderWrapper = $('<div class="page-view-wrapper dropdown pull-left">\
<span class="btn toggle-dropdown">'+ iconSVg + '</span>\
<span class="page-view-counter" title="阅读数">-</span>\
</div>')

if(lastChild.length){
renderWrapper.insertBefore(lastChild)
}else{
bookHeader.append(renderWrapper)
}

var Counter = function (method, url, data) {
return $.ajax({
method: method,
url : `http://127.0.0.1:8080${url}`,
data: data,
});
};

var url = location.href.replace(/^http:\/\/[^/]+/, "").trim();
url = decodeURI(url);
var s = url.split("/").pop();
var title = s.replace(".html", "");
var time = 0;

Counter('get', '/counter', { url: url }).done(function (results ) {
console.log(results)
if (results.time > 0) {
time = results.time+1;
Counter('put', `/counter`, {url: url, time: time }).done(function () {
console.log(time);
renderWrapper.find('.page-view-counter').html(time)
})
} else {
Counter('post', '/counter', { title: title, url: url, time: 1}).done(function ({ results }) {
renderWrapper.find('.page-view-counter').html(1)
})
}
});

})
});

仓库地址:https://github.com/TiannV/gitbook-plugin-mf-pageview
npm publish发布到npm市场
5

使用

添加插件

在自己的gitbook仓库的book.json文件添加插件
6

7

执行gitbook install即可将应用市场上的插件下载到gitbook项目中
gitboolk build 执行编译

运行数据库连接服务

go run mf.go

8

启动gitbook

gitbook serve

9

查看界面:
10
成功~

代码仓库

TiannV/gitbook-plugin-mf-pageview