MemFireDB实现gitbook文章阅读量插件

背景

个人开发者普遍拥有属于自己的个人博客站点。常见的框架无论是Hexo、Gitbook,亦或是Docsify,这些框架本身并不支持文章阅读量或者站点访问量的功能,需要各种对应的插件支持。
目前市面上这些插件基本上是基于busuanzi,LeanCloud实现的,而Memfire旨在提供数据库服务,若后续提供sdk功能,能够实现对应框架的插件供个人开发者使用,并提供相关文章,也能吸引很多个人开发者。(因为我本身也是基于使用插件的需要,才在LeanCloud上注册了账户。)

概述

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

实现

建库建表

登录MemFireDB Cloud

需要在MemFireDB Cloud上注册账户,并创建自己的数据库
在这里插入图片描述

进入在线编辑器

点击SQL查询进入在线编辑器
在这里插入图片描述

建表

CREATE TABLE counter (
  id serial NOT NULL,
  url varchar(500),
  time int,
  title varchar(200),
        PRIMARY KEY (id)
)

在这里插入图片描述

数据库连接

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

package main

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

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

const (
  host     = "<db ip>"
  port     = <db port>
  user     = "<your db user>"
  password = "<your db password>"
  dbname   = "<your db name>"
)

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插件

仿造其他插件,建立代码仓库
在这里插入图片描述

修改book下plugin.js

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市场
在这里插入图片描述

使用

添加插件

在自己的gitbook仓库的book.json文件添加插件
在这里插入图片描述
在这里插入图片描述

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

运行数据库连接服务

go run mf.go
在这里插入图片描述

启动gitbook

gitbook serve
在这里插入图片描述

查看界面:
在这里插入图片描述

成功~

代码仓库

TiannV/gitbook-plugin-mf-pageview

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值