<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          博客抽風(fēng)了,為了這又浪費了我寶貴的一天!

          共 27550字,需瀏覽 56分鐘

           ·

          2022-06-19 13:08

          一開始博客使用的 Halo,發(fā)現(xiàn)問題比較多啊,時不時的莫名其妙主題各種報錯,有時候還要升級,麻煩的要死,于是就想弄簡單點。

          這兩天抽空反復(fù)倒騰了一遍,不小心還把鏡像給尼瑪刪了,發(fā)的文章都沒了,痛定思痛,要做改變!

          眾所周知,我懶出名了,我覺得這種事情你不要老是讓我操心啊,最好是一年都不要動一下才好,這搞的跟什么一樣。

          研究一會兒,最終還是決定 docsify+github 來弄,初步的想法是本地寫好 MD 文件直接 push 到 github上,然后觸發(fā) github 的webhook,觸發(fā)腳本去 pull 代碼到服務(wù)器上。

          博客

          這樣的話還有點想象空間,以后可以省去一大部分同步文章的工作,都可以出發(fā)回調(diào)去通過 API 同步,不過暫時還沒有調(diào)研這些平臺是否能支持,不過應(yīng)該問題不大。

          試試解決方案可不可行吧,我覺得很 nice。

          docsify 搭建安裝

          首先安裝 docsify-cli 工具

          npm i docsify-cli -g

          然后進入自己的目錄,初始化

          docsify init ./

          這樣就差不多了,多了幾個文件,簡單修改一下 index.html,配置下名字和代碼倉庫的信息,開啟下左邊的側(cè)邊欄。

          同時補充一點插件,都從網(wǎng)上摟的。

          <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <title>Document</title>
            <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
            <meta name="description" content="Description">
            <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
            <link rel="stylesheet" ></script> -->
          </body>
          </html>

          然后運行,本地會啟動 http://localhost:3000,直接看看效果

          docsify serve

          大概就這個樣子了

          側(cè)邊欄還沒有,使用命令生成一下,會自動幫我們根據(jù)目錄創(chuàng)建一個_sidebar.md文件,也就是我們的側(cè)邊欄了。

          docsify generate .

          然后再看看效果怎么樣,差不多就這樣,需要注意的是文件名不能有空格,否則生成的側(cè)邊欄目錄會有問題,需要修改一下文件名使用中劃線或者下?lián)Q線替換空格(我無法理解為什么不能用空格)。

          多級目錄生成問題

          另外還有一個問題是無法生成多級目錄,也就是不能超過二級目錄,這個我自己隨便改了一下。

          去 docsify-cli 官方 git 倉庫下載源碼,然后把這個丟進去,在目錄下執(zhí)行 node generate.js 就可以,底部測試目錄改成自己的目錄。

          'use strict'

          const fs = require('fs')
          const os = require('os')
          const {cwd, exists} = require('../util')
          const path = require('path')
          const logger = require('../util/logger')
          const ignoreFiles = ['_navbar''_coverpage''_sidebar']

          // eslint-disable-next-line
          function test (path = '', sidebar{
            // 獲取當(dāng)前目錄
            const cwdPath = cwd(path || '.')

            // console.log('cwdPath', cwdPath, !!exists(cwdPath));

            // console.log('///////', cwdPath, path, cwd(path || '.'))
            if (exists(cwdPath)) {
              if (sidebar) {
                const sidebarPath = cwdPath + '/' + sidebar || '_sidebar.md';

                if (!exists(sidebarPath)) {
                  genSidebar(cwdPath, sidebarPath)
                  logger.success(`Successfully generated the sidebar file '${sidebar}'.`)
                  return true
                }

                logger.error(`The sidebar file '${sidebar}' already exists.`)
                process.exitCode = 1
                return false
              }
              return false;
            }

            logger.error(`${cwdPath} directory does not exist.`)
          }

          let tree = '';
          function genSidebar(cwdPath, sidebarPath{
            // let tree = '';
            let lastPath = ''
            let nodeName = ''
            let blankspace = '';
            let test = 0;

            const files = getFiles(cwdPath);
            console.log(JSON.stringify(files));
            getTree(files);

            fs.writeFile(sidebarPath, tree, 'utf8', err => {
              if (err) {
                logger.error(`Couldn't generate the sidebar file, error: ${err.message}`)
              }
            })

            return;

            getDirFiles(cwdPath, function (pathname{
              path.relative(pathname, cwdPath) // 找cwdPath的相對路徑
              pathname = pathname.replace(cwdPath + '/''')
              let filename = path.basename(pathname, '.md'// 文件名
              let splitPath = pathname.split(path.sep) // 路徑分割成數(shù)組
              let blankspace = '';

              if (ignoreFiles.indexOf(filename) !== -1) {
                return true
              }

              nodeName = '- [' + toCamelCase(filename) + '](' + pathname + ')' + os.EOL

              if (splitPath.length > 1) {
                if (splitPath[0] !== lastPath) {
                  lastPath = splitPath[0]
                  tree += os.EOL + '- ' + toCamelCase(splitPath[0]) + os.EOL
                }
                tree += '  ' + nodeName
                // console.error('tree=====', tree, splitPath, splitPath.length);
              } else {
                if (lastPath !== '') {
                  lastPath = ''
                  tree += os.EOL
                }

                tree += nodeName
              }
            })
            fs.writeFile(sidebarPath, tree, 'utf8', err => {
              if (err) {
                logger.error(`Couldn't generate the sidebar file, error: ${err.message}`)
              }
            })
          }

          function getFiles (dir{
            // let path = require('path');
            // let fs = require('fs');
            let rootDir = dir;
            var filesNameArr = []
            let cur = 0
            // 用個hash隊列保存每個目錄的深度
            var mapDeep = {}
            mapDeep[dir] = 0
            // 先遍歷一遍給其建立深度索引
            function getMap(dir, curIndex{
              var files = fs.readdirSync(dir) //同步拿到文件目錄下的所有文件名
              files.map(function (file{
                //var subPath = path.resolve(dir, file) //拼接為絕對路徑
                var subPath = path.join(dir, file) //拼接為相對路徑
                var stats = fs.statSync(subPath) //拿到文件信息對象
                // 必須過濾掉node_modules文件夾
                if (file != 'node_modules') {
                  mapDeep[file] = curIndex + 1
                  if (stats.isDirectory()) { //判斷是否為文件夾類型
                    return getMap(subPath, mapDeep[file]) //遞歸讀取文件夾
                  }
                }
              })
            }
            getMap(dir, mapDeep[dir])
            function readdirs(dir, folderName, myroot{
              var result = { //構(gòu)造文件夾數(shù)據(jù)
                path: dir,
                title: path.basename(dir),
                type'directory',
                deep: mapDeep[folderName]
              }
              var files = fs.readdirSync(dir) //同步拿到文件目錄下的所有文件名
              result.children = files.map(function (file{
                //var subPath = path.resolve(dir, file) //拼接為絕對路徑
                var subPath = path.join(dir, file) //拼接為相對路徑
                var stats = fs.statSync(subPath) //拿到文件信息對象
                if (stats.isDirectory()) { //判斷是否為文件夾類型
                  return readdirs(subPath, file, file) //遞歸讀取文件夾
                }
                if (path.extname(file) === '.md') {
                  const path =  subPath.replace(rootDir + '/''');
                  // console.log(subPath, rootDir, '========', path);
                  return { //構(gòu)造文件數(shù)據(jù)
                    path: path,
                    name: file,
                    type'file',
                    deep: mapDeep[folderName] + 1,
                  }
                }
              })
              return result //返回數(shù)據(jù)
            }
            filesNameArr.push(readdirs(dir, dir))
            return filesNameArr
          }

          function getTree(files{
            for (let i=0; i<files.length;i++) {
              const item = files[i];
              if (item) {
                if (item.deep === 0) {
                  if (item.children) {
                    getTree(item.children)
                  }
                } else {
                  let blankspace = ''
                  for (let i = 1; i < item.deep; i++) {
                    blankspace += '  '
                  }
                  // console.log('-' + blankspace + '-', item.deep)
                  if (item.type === 'directory') {
                    tree += os.EOL + blankspace + '- ' + toCamelCase(item.title) + os.EOL
                  } else if (item.type === 'file') {
                    tree += os.EOL + blankspace + '- [' + item.name + '](' + item.path + ')' + os.EOL
                    // console.log('tree', tree);
                  }
                  if (item.children) {
                    getTree(item.children)
                  }
                }
              }
            }
          }

          function getDirFiles(dir, callback{
            fs.readdirSync(dir).forEach(function (file{
              let pathname = path.join(dir, file)

              if (fs.statSync(pathname).isDirectory()) {
                getDirFiles(pathname, callback)
              } else if (path.extname(file) === '.md') {
                callback(pathname)
              }
            })
          }

          function toCamelCase(str{
            return str.replace(/\b(\w)/gfunction (match, capture{
              return capture.toUpperCase()
            }).replace(/-|_/g' ')
          }


          test("/Users/user/Documents/JavaInterview/""sidebar.md");

          這樣的話一切不就都好起來了嗎?看看最終的效果。

          nginx 配置

          webhook 暫時還沒弄,先手動 push 上去然后把文件都傳到服務(wù)器上去,再設(shè)置一下 nginx 。

          server {
          listen 80;
          listen [::]:80;
          server_name aixiaoxian.vip;
          client_max_body_size 1024m;
          location / {
          root /你的目錄;
          index index.html;
          }
          }

          server {
          listen 443 ssl;
          server_name aixiaoxian.vip;
          root /usr/share/nginx/html;

          ssl_certificate cert/aixiaoxian.pem;
          ssl_certificate_key cert/aixiaoxian.key;
          ssl_session_cache shared:SSL:1m;
          ssl_session_timeout 10m;
          ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
          ssl_prefer_server_ciphers on;
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #表示使用的TLS協(xié)議的類型。
          include /etc/nginx/default.d/*.conf;

          location / {
          root /你的目錄;
          index index.html;
          }
          }

          這時候你去 reload nginx 會發(fā)現(xiàn)網(wǎng)站可能 403 了,把你的 ng 文件第一行改了,甭管后面是啥,改成 root 完事兒。

          user root;

          這樣就 OK 了。

          內(nèi)網(wǎng)穿透

          然后,就需要搞一個 webhook 的程序了,但是在此之前,為了本地能測試 webhook 的效果,需要配置個內(nèi)網(wǎng)穿透的程序,我們使用 ngrok 。

          先安裝。

          brew install ngrok/ngrok/ngrok

          然后需要注冊一個賬號,這里沒關(guān)系,直接 google 登錄就好了,之后進入個人頁面會提示你使用步驟。

          按照步驟來添加 token,然后映射 80 端口。

          如果后面發(fā)現(xiàn) ngrok 命令找不到,可以去官網(wǎng)手動下一個文件,丟到/usr/local/bin目錄中就可以了。

          成功之后可以看到 ngrok 的頁面,使用他給我們提供的 Forwarding 地址,就是我們的公網(wǎng)地址。

          我隨便弄了個 80 端口,這里用自己到時候項目的端口號映射就行了,后面我們改成 9000。

          webhook

          配置好之后,就去我們的 github 項目設(shè)置 webhook,使用上面得到的地址。

          這樣就設(shè)置OK了,然后搞個 Java 程序去,監(jiān)聽 9000 端口,隨便寫個 Controller

          @PostMapping("/webhook")
          public void webhook(@RequestBody JsonNode jsonNode) {
           System.out.println("json===" + jsonNode);
          }

          然后隨便改點我們的文檔,push 一下,收到了 webhook 的回調(diào),其實我們根本不關(guān)注回調(diào)的內(nèi)容,我們只要收到這個通知,就去觸發(fā)重新拉取代碼的指令就行。

          {
              "repository": {
                  "id"306793662,
                  "name""JavaInterview",
                  "full_name""irwinai/JavaInterview",
                  "private"false,
                  "owner": {
                      "name""irwinai",
                      "email""[email protected]",
                      "login""irwinai"
                  },
                  "html_url""https://github.com/irwinai/JavaInterview",
                  "description"null,
                  "fork"false
              },
              "pusher": {
                  "name""irwinai",
                  "email""[email protected]"
              },
              "sender": {
                  "login""irwinai",
                  "id"4981449
              }
          }

          接著,我們實現(xiàn)代碼邏輯,根據(jù)回調(diào)執(zhí)行命令去拉取最新的代碼到本地,為了能通過 Java 操作 Git,引入 JGit。

          <dependency>
            <groupId>org.eclipse.jgit</groupId>
            <artifactId>org.eclipse.jgit</artifactId>
            <version>5.13.1.202206130422-r</version>
          </dependency>

          為了簡單,我每次都是重新 clone 倉庫下來,正常來說應(yīng)該第一次 clone,后面直接 pull 代碼,這里為了省事兒,就先這樣操作。

          @RestController
          public class WebhookController {
              private static final String REMOTE_URL = "https://github.com/irwinai/JavaInterview.git";

              @PostMapping("/webhook")
              public void webhook(@RequestBody JsonNode jsonNode) throws Exception {
                  File localPath = new File("/Users/user/Downloads/TestGitRepository");

                  // 不管那么多,先刪了再說
                  FileUtils.deleteDirectory(localPath);

                  //直接 clone 代碼
                  try (Git result = Git.cloneRepository()
                          .setURI(REMOTE_URL)
                          .setDirectory(localPath)
                          .setProgressMonitor(new SimpleProgressMonitor())
                          .call()) {
                      System.out.println("Having repository: " + result.getRepository().getDirectory());
                  }
              }

              private static class SimpleProgressMonitor implements ProgressMonitor {
                  @Override
                  public void start(int totalTasks) {
                      System.out.println("Starting work on " + totalTasks + " tasks");
                  }

                  @Override
                  public void beginTask(String title, int totalWork) {
                      System.out.println("Start " + title + ": " + totalWork);
                  }

                  @Override
                  public void update(int completed) {
                      System.out.print(completed + "-");
                  }

                  @Override
                  public void endTask() {
                      System.out.println("Done");
                  }

                  @Override
                  public boolean isCancelled() {
                      return false;
                  }
              }
          }

          代碼執(zhí)行后已經(jīng)是 OK 了,可以直接拉取到代碼,那么至此,差不多已經(jīng) OK 了,后面把代碼直接丟服務(wù)器上去跑著就拉倒了。

          服務(wù)器的問題

          好了,你以為到這里就結(jié)束了嗎?年輕了,年輕了。。。

          這代碼丟到服務(wù)器上跑會發(fā)現(xiàn)報錯連不上 github,如果你是阿里云服務(wù)器的話。

          解決方案是找到 /etc/ssh/ssh_config,刪掉 GSSAPIAuthentication no 這行前面的注釋,然后保存,你才會發(fā)現(xiàn)真的是能下載了。

          同時,nginx 我們映射另外一個域名作為回調(diào)的域名,這里需要主要以下你的 https 證書,因為我是免費版的,所以 https 這個域名無法生效,那 webhook 回調(diào)注意用 http 就行。

          server {
          listen 80;
          listen [::]:80;
          server_name test.aixiaoxian.vip;
          client_max_body_size 1024m;
          location / {
          proxy_pass http://127.0.0.1:9000;
          proxy_set_header HOST $host;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          }
          }
          server {
          listen 443 ssl;
          server_name test.aixiaoxian.vip;
          root /usr/share/nginx/html;

          ssl_certificate cert/aixiaoxian.pem;
          ssl_certificate_key cert/aixiaoxian.key;
          ssl_session_cache shared:SSL:1m;
          ssl_session_timeout 10m;
          ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
          ssl_prefer_server_ciphers on;
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #表示使用的TLS協(xié)議的類型。
          include /etc/nginx/default.d/*.conf;

          location / {
          proxy_pass http://127.0.0.1:9000;
          proxy_set_header HOST $host;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          }
          }

          OK,如果你用上面的方式還無法解決,可以換一種方式,直接通過 Java 直接 shell 腳本去處理。

          rm -rf /root/docs/JavaInterview
          git clone https://github.91chi.fun//https://github.com/irwinai/JavaInterview.git

          用腳本的目的是可以用加速的 git 地址,否則服務(wù)器訪問經(jīng)常會失敗,這個找個插件就可以有加速地址了。

          public class ShellCommandsHelper extends CommandHelper {
              private static final File file = new File(FILE_PATH);

              @Override
              public void exec() {
                  try {
                      FileUtils.forceMkdir(file);

                      log.info("Starting clone repository...");

                      Process process = Runtime.getRuntime().exec("sh " + SHELL_PATH, null, file);
                      int status = process.waitFor();

                      if (status != 0) {
                          log.error("[ShellCommandsHelper] exec shell error {}", status);
                      }
                  } catch (Exception e) {
                      log.error("[ShellCommandsHelper] exec shell error", e);
                  }
              }

          }

          代碼上傳的問題

          好了,這樣通過手動上傳代碼的方式其實已經(jīng)可以用了,但是為了部署更方便一點,我建議安裝一個插件Alibaba Cloud Toolkit,其他云服務(wù)器有的也有這種類型的插件。

          安裝好插件之后會進入配置的頁面,需要配置一個accessKey。

          去自己的阿里云賬號下面配置。

          配置好了之后,點擊Tools-Deploy to xxx,我是 ECS ,所以選擇 ECS 服務(wù)器即可。

          然后在這里會自動加載出你的服務(wù)器信息,然后選擇自己的部署目錄,同時選擇一個 Command 也就是執(zhí)行命令。

          這個命令隨便找個目錄創(chuàng)建一個這個腳本,放那里就行了,最后點擊 Run,代碼就飛快的上傳了。

          source /etc/profile
          killall -9 java
          nohup java -jar /root/tools/sync-tools-0.0.1-SNAPSHOT.jar > nohup.log 2>&1 &

          結(jié)束

          基本的工作已經(jīng)做完了,那其實還有挺多細節(jié)問題沒有處理的,比如失敗重試、回調(diào)鑒權(quán)等等問題,這只是一個非常初級的版本。

          同步代碼 git 地址:https://github.com/irwinai/sync-tools

          文章倉庫地址:https://github.com/irwinai/JavaInterview

          博客地址:https://aixiaoxian.vip/#/



          瀏覽 83
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲国产欧美久久 | 亚洲天堂精品在线观看 | 亚洲黄色小视频 | 4438成人网222 51精品一区二区三区 | 狠狠操无码免费 |