RabbitMQ 是一个使用 Erlang 编写的消息队列的实现,能够接收并转发消息。
RabbitMQ is open source message broker software (sometimes called message-oriented middleware) that implements the Advanced Message Queuing Protocol (AMQP). The RabbitMQ server is written in the Erlang programming language and is built on the Open Telecom Platform framework for clustering and failover. Client libraries to interface with the broker are available for all major programming languages.
各个平台的安装官网都非常详细: https://www.rabbitmq.com/download.html
各个语言的客户端:https://www.rabbitmq.com/devtools.html
apt install rabbitmq-server
docker pull rabbitmq
docker run -d -p 15672:15672 -p 5672:5672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin --name rabbitmq --hostname=rabbitmq rabbitmq:latest
rabbitmq 默认的 latest tag 是不带管理页面的如果是要管理页面需要使用 rabbitmq:3-management
docker run -d -p 15672:15672 -p 5672:5672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin --name rabbitmq --hostname=rabbitmq rabbitmq:3-management
启动之后访问 http://ip:15672 就能够访问管理后台
列出当前 RabbitMQ 中的队列
sudo rabbitmqctl list_queues
列出 exchange
sudo rabbitmqctl list_exchanges
各个客户端的教程官方的教程非常详细可以直接参考。
linux中的ip命令和ifconfig类似,但前者功能更强大,并旨在取代后者。ifconfig是net-tools
中已被废弃使用的一个命令。iproute2 套件里提供了许多增强功能的命令,ip命令即是其中之一。只需一个ip命令,就能很轻松地执行一些网络管理任务。
给机器设置一个IP地址
sudo ip addr add 192.168.0.193/24 dev wlan0
列出路由表条目
ip route show
显示网络统计数据
ip -s link
在 Flask 中使用 Celery 官方给出了一个非常详细的教程,可是这个教程中有一点没有讲清楚,就是关于引入了 Celery 之后如何在项目中划分模块以及模块之间的相互调用,我们知道 Flask 用于构建比较大的项目时可能会使用到 blueprints,而这个时候项目结构可能就比较复杂了。
而引入 Celery 直接面临的问题是如何初始化 Celery 实例,在创建 Flask app 的同时创建 Celery 实例,这时候就面临一个问题,通常我们都在 Views 中引用 celery 异步任务,不可避免的会导致,需要在 views 中 import celery 相关的 module,而 celery 相关的 module 会引入 Flask app 相关的内容,而 Flask app 初始化会引入 views 相关的内容,就变成了循环调用。
有一个比较简单的解法就是初始化两个 Flask App 实例,一个用来启动,一个用来给 Celery 创造上下文。
不要在 create_app()
中再创建 Celery 实例。比如新建 celery_worker.py
来初始化 celery 实例,而在另外的文件中初始化 Flask()
实例。
项目结构大致如下:
├── README.md
├── app
│ ├── __init__.py
│ ├── config.py
│ ├── forms
│ ├── models
│ ├── tasks
│ │ ├── __init__.py
│ │ └── email.py
│ └── views
│ │ ├── __init__.py
│ │ └── account.py
├── celery_worker.py
├── manage.py
└── wsgi.py
图中
在 app/__init__.py
from celery import Celery
from flask import Flask
from app.config import BaseConfig
celery = Celery(__name__, broker=BaseConfig.CELERY_BROKER_URL)
def create_app():
app = Flask(__name__)
# ....
celery.conf.update(app.config) # 更新 celery 的配置
# ...
return app
在 celery_worker.py
from app import create_app, celery
app = create_app()
app.app_context().push()
这个文件有两个操作,一个为初始化 Flask 实例,也就初始化了 Celery 实例,然后第二个操作是使用 Flask 的 application context,celery 的所有操作都会在这个环境中执行。
然后就可以启动 Celery celery worker -A celery_worker.celery -l INFO
这里便引出了另外一个问题,如何在 Flask 外部使用 SQLAlchemy 中定义好的 model,当我们定义好和数据库相对应的 Object 之后,难免有些时候需要在 Flask 外部使用,比如清洗一些数据,或者单独跑一些数据时,这时没有 Flask Context 环境,那么这个时候需要借助 app_context()
函数:
from my_package import create_app
app = create_app(my_envrionment)
with app.app_context():
# your code here
在 Context 上下文环境中就能够使用定义好的 model 了。另外一种方法是使用 @with_appcontext
装饰器:
from flask.cli import with_appcontext
@click.command(name='db-init-data')
@with_appcontext
def db_init_data():
"""Init db with some data"""
admin = User(fname='John', lname='Smith', email='jsmith@google.com')
db.session.add(admin)
db.session.commit()
k3 的折腾记录
我的固件版本 V21.6.12.66
只要两步,WEB 直刷,就能降级
K3_V21.6.11.58P 下载地址
链接:https://pan.baidu.com/s/1rasSyjq 密码:ksxp
K3_V21.5.37.246 下载地址
链接:https://pan.baidu.com/s/1mjv2jaC 密码:xmrh
使用这个教程 激活 Telnet 端口
然后备份路由器
telnet 192.168.2.1
mount # 查看当前挂载的 U 盘
cd /tmp/share/sda1/
mkdir backup
cd backup
cat /dev/mtdblock0 > mtdblock0.bin # 备份 CFE
cat /dev/mtdblock5 > mtdblock5.bin # 备份设备信息
cat /dev/mtdblock6 > mtdblock6.bin # 备份固件,备份固件时间可能有些长 1min 左右
这个几个分区的作用
对于 K3 官方固件:
mtd0 boot
cfe 引导分区,建议备份,还包含了部分 nvram 参数和 MAC 等信息,不要刷入别人的,也不要随意刷写这个分区。
mtd1 nvram
设置分区,不用备份,保存了路由的所有设置信息,恢复出厂时会格式化然后从 cfe 和当前固件复制默认参数。
mtd2 nvram_back
从名字看像是 nvram 的备份,实际固件没有使用,全部空白,不用备份。
mtd3 res_info
没有使用,全部空白,不用备份。
mtd4 pro_info
只有 6 字节数据,00904C17F234,所有机器都一样,可选备份,就算没备份把这 6 字节复制过去就恢复了。
mtd5 dev_info
176 字节数据,好像是加密的固件的版本一些信息,刷写官方固件版本号发生变化时候这里的数据就变化,可选备份。
mtd6 linux
整个固件分区,平常刷写官方固件或者 LEDE 都是刷到这里,官方提供固件下载,只要 cfe 正常随便刷,不用备份。
mtd7 rootfs
动态的,包含在 linux 分区,mtd6 减去当前固件内核部分,是固件的后半部分,而固件是一个整体,当然不用备份。
mtd8 brcmnand
存储分区,日志文件、自己安装的软件保存再这里,固件版本信息变化时系统会格式化,不用备份,也不要恢复。
这里我使用 abccba94 官改固件,在页面下载固件,现在最新的已经到了 k3_v16d ,解压,得到 k3_v16d.bin 文件,复制到 U 盘,如果 U 盘还连在路由器,可以使用 \192.168.2.1\ 然后远程将文件拷贝到 U 盘中。
然后在登录 telnet 192.168.2.1
cd /tmp/share/sda1/
cat k3_v16d.bin > /dev/mtdblock6 && reboot
将该目录下固件刷入,等待重启之后,做一次恢复出厂设置,长按 reset 键 5 秒。
K3 的固件整理大全
在管理后台软件中心安装 entware 之后,可以使用命令安装很多扩展。
entware 中的包列表:
http://pkg.entware.net/binaries/armv7/Packages.html
安装 ttyd
opkg install ttyd
然后在 webshell 中设置开启网页管理,那么直接访问 http://ip:7681 ,输入用户名和密码就能够在网页中管理路由器。
ttyd 开源在 GitHub,使用 C 语言,websocket 通信。
更多有趣的包可以查看这里
手机移动端 SSH 工具:
IOS:Termius、Prompt 2 Android:JuiceSSH、ConnectBot、Termius
K3 的 SSH 用户名是 admin,密码是网页管理密码。(网页管理密码和 SSH 密码是分开保存的,如果你开机后改过网页密码(比如执行恢复出厂设置相当于改成预置的 admin),ssh 密码不会立即同步,重启之后才会同步网页的管理密码)
我一直用的是 Cinnamon 的桌面环境,使用 icon 主题也比较方便,这里就做个记录。
地址:
安装
sudo add-apt-repository ppa:papirus/papirus
sudo apt-get update
sudo apt-get install papirus-icon-theme
地址
安装
sudo add-apt-repository ppa:noobslab/icons
sudo apt-get update
sudo apt-get install ultra-flat-icons
更多的 ICON 主题可以看
自己的 yourls 已经搭建完毕 ,重要的就是如何高效的用起来了, yourls 自身提供了很不错的快速访问工具,安装完毕之后直接浏览
https://域名/admin/tools.php
可以得到书签栏中的快速访问工具,直接拖拽到浏览器的地址栏就可以快速的将当前的页面地址缩短。这个工具也就不多介绍了,这篇文章主要摸索一下 yourls 的API调用,以及如何在PC,和移动端快速的使用短链接服务。
yourls 提供了丰富的API,使用自身的API可以实现
请求的地址
https://域名/yourls-api.php
通过 GET 或者 POST 请求(GET请求需要URL Encode)
两种方式获得授权,一种是使用 username
/ password
对发送请求,但是这种方式不安全,可能导致用户名密码在传输过程中被截取泄露;另一种方式是使用不需要密码的 token 机制,在 admin/tools.php 页面会产生当前用户的验证 token。
动作 action
参数有很多个选项
shorturl
获取链接的短链接
在使用了值之后,另外两个参数
- `url` 用来缩短的原始链接
- `keyword` 或者 `title` 可选参数,用来自定义短链接
expand
获取短链接的原始长链接
将短链接展开
- `shorturl` 值可以为 `abc` 或者完整的短链接
url-stats
获取短链接的信息
短链接的统计信息
- `shorturl` 值可以为 `abc` 或者完整的短链接
stats
获取链接的信息
获取链接的信息
- `filter` 值可以为 `top`, `bottom`, `rand`, `last`
- `limit` 返回的数量
db-stats
获取全局的链接和点击数
输出格式 format
参数用来指定API输出的格式,有如下值
请求缩短链接
curl -X POST \
https://gtk.pw/yourls-api.php \
-F signature=xxxxxx \
-F action=shorturl \
-F url=https://gtk.pw/readme.html \
-F format=json
返回结果
因为之前已经请求过,所以报了fail,不过结果依然能够从 shorturl
中拿到
{
"status": "fail",
"code": "error:url",
"url": {
"keyword": "OStH3",
"url": "https://gtk.pw/readme.html",
"title": "YOURLS: Your Own URL Shortener",
"date": "2018-05-18 03:27:36",
"ip": "123.123.123.7",
"clicks": "0"
},
"message": "https://gtk.pw/readme.html already exists in database",
"title": "YOURLS: Your Own URL Shortener",
"shorturl": "https://gtk.pw/OStH3",
"statusCode": 200
}
其他几个API同理,返回结果结构稍有差异不过都类似。
iOS 上可以借助 Workflow 快速实现,主要的步骤
然后每一次将链接复制到粘贴板,然后运行该 workflow ,短链接就在 Clipboard 中了。
第二中方法,是直接在浏览器中,在链接前面加上,yourls 的域名,比如
https://blog.einverne.info
加入yourls 的域名是 https://gtk.pw
那么在链接前加上 gtk.pw,yourls 会跳转到 admin 页面并添加该链接
gtk.pw/https://blog.einverne.info
其他平台同理,不过需要登录 admin 略麻烦。
之前安装 Chevereto 时还没有折腾 Docker,后来发现 Docker 安装 实在太方便了,所以现在就将数据迁移到 Docker 中,备份和恢复的方式主要可以参考之前写的文章。
对于 Chevereto 这样的程序主要备份的就是数据库和文件,mysql 备份没啥说的,文件也直接打包即可。
这里主要展开下恢复,一方面在 docker-compose.yml 文件中,我映射列两个 volumes,
volumes:
- chevereto:/var/www/html/images
- chevereto_content:/var/www/html/content
这两个文件路径,images 主要存放的是上传的图片,而 content 目录一开始的时候我们并没有加上,导致一些系统的 logo 还有用户的头像消失了,我对比了下目录中存放的文件,发现 Chevereto 将这些资源文件存放在了 content 目录中,映射出来,然后恢复的时候将之前备份的内容恢复到这两个目录即可。
数据库恢复也比较容易
sudo cat backup.sql | sudo docker exec -i chevereto_db /usr/bin/mysql -u root --password=password chevereto
然后文件恢复时直接恢复到 volumes 的目录,sudo docker volume inspect volume_name
然后查看 volume 的位置,将文件解压到该目录下。
Chevereto 两个挂载的路径是
/var/lib/docker/volumes/chevereto_chevereto/_data
/var/lib/docker/volumes/chevereto_chevereto_content/_data
然后 chown www-data:www-data *
来改变权限即可。
这个备份和恢复的操作同理可以应用到任何类似 WordPress,Chevereto 这样的 PHP 应用上。
HTTP 协议全称 Hyper Text Transfer Protocol 超文本传输协议,基于 TCP/IP 协议用来传递数据。HTTP 面向应用层,HTTP协议是万维网的基石。
HTTP请求由以下部分组成
根据HTTP标准,HTTP请求可以使用多种请求方法。
Referer 头允许客户端指定请求的URI的源地址,服务端通过检查该头信息可以知道客户端请求的资源的原始来源。
HTTP 1.1 中请求和应答头都可能出现 Connection ,表示 client 和 server 通信时对于长连接如何处理。
HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
看到一篇使用信鸽来解释HTTPS的文章,信息量足够,也很生动的解释了非对称加密以及产生的问题和解法。
通过信鸽传递盒子,解释了HTTPS的非对称加密公私钥的问题
盒子是公钥,而爱丽丝手上的钥匙是私钥
如何信任盒子一节引入泰德这个第三方签名,在HTTPS中是认证机构。而沉重的盒子这一个小节,总结了HTTPS存在的问题,虽然加密的HTTPS要慢,但未来的趋势已经不可避免了。
长连接,也叫持久连接,在TCP层握手成功后,不立即断开连接,并在此连接的基础上进行多次消息(包括心跳)交互,直至连接的任意一方(客户端OR服务端)主动断开连接,此过程称为一次完整的长连接。HTTP 1.1 相对于1.0 最重要的新特性就是引入了长连接。
短连接,顾名思义,与长连接的区别就是,客户端收到服务端的响应后,立刻发送FIN消息,主动释放连接。也有服务端主动断连的情况,凡是在一次消息交互(发请求-收响应)之后立刻断开连接的情况都称为短连接。
注:短连接是建立在TCP协议上的,有完整的握手挥手流程,区别于UDP协议。
需要频繁交互的场景使用长连接,如即时通信工具(微信/QQ,QQ也有UDP),相反则使用短连接,比如普通的web网站,只有当浏览器发起请求时才会建立连接,服务器返回相应后,连接立即断开。
维持长连接会有一定的系统开销,用户量少不容易看出系统瓶颈,一旦用户量上去了,就很有可能把服务器资源(内存/CPU/网卡)耗尽,所以使用需谨慎。
HTTP 协议 redirect 有两个状态码 301 和 302,对于这两个状态码协议上是这么写的
浏览器在处理这两个状态码时行为不一样,对于 Chrome / Firefox 会永久的缓存 301 跳转1,浏览器会尽可能的永久保存该跳转,除非手动清除浏览器缓存,或者浏览器缓存将满为新内容腾出空间。如果不想跳转被浏览器缓存,可以使用 Cache-Control
和 Expires
两个头。
关于Chrome中如何清除永久的301跳转可以参考这篇文章
https://stackoverflow.com/a/21396547/1820217 ↩
最近在学习使用 Flask 生成一个短链接服务时看到了 Flask-Migrate 这样一款插件,之前学习 Django 的时候自带数据库迁移工具, Flask 中也有这样一款,不过是以插件的形式出现,Flask Migrate 基于 Alembic ,Alembic 是 SQLAlchemy 作者开发的数据迁移工具。
文档主页:https://flask-migrate.readthedocs.io/en/latest/
执行:
pip install Flask-Migrate
在安装完成之后需要在代码中添加如下代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
在添加代码之后需要运行
flask db init
来初始化项目,命令运行之后会在项目中生成 migrations
文件夹,该文件夹需要添加到版本控制。
之后可以使用 migrate
命令来初始化迁移
flask db migrate
迁移脚本不会检测 models 的所有变更, Alembic 目前无法检测表名修改,列名修改,其他限制可以在 Alembic 网站 查看。
之后可以应用该迁移
flask db upgrade
运行该命令来将修改应用到数据库,以后对 model 的每一次修改需要重复 migrate
和 upgrade
命令。如果要在不同机器之间同步数据库结构,只需要同步 migrations 文件夹,并且在另一台机器上运行 flask db upgrade
即可。
Flask Migrate 也支持直接使用脚本的方式运行,具体可参考 官方的文档 ,非常易懂。
Flask-Migrate 还支持降级:
flask db downgrade
(venv) $ flask db
Usage: flask db [OPTIONS] COMMAND [ARGS]...
Perform database migrations.
Options:
--help Show this message and exit.
Commands:
branches Show current branch points
current Display the current revision for each...
downgrade Revert to a previous version
edit Edit a revision file
heads Show current available heads in the script...
history List changeset scripts in chronological...
init Creates a new migration repository.
merge Merge two revisions together, creating a new...
migrate Autogenerate a new revision file (Alias for...
revision Create a new revision file.
show Show the revision denoted by the given...
stamp 'stamp' the revision table with the given...
upgrade Upgrade to a later version
假如已经有数据库表结构了,后期引入了 Flask-Migrate,那么可以通过如下步骤集成 Flask-Migrate 到项目中。
flask db init
创建新的 migrationflask db migrate
来初始化已经存在的 migrationflask db stamp head
这一步会在数据库创建 alembic_version
表,然后保存最新的 migration 版本之后就可以使用 Migration 来管理数据库版本了。
flask db migrate
flask db upgrade
Migrations 总是在开发环境中生成。
生产环境中只会应用变更(upgrade)。
之前在做一次 Vim 演示的时候想要更加直观的在屏幕上实时显示出当前敲击的字母,所以找到了 screencast 这个解决方法。
Debian/Ubuntu:
首先安装依赖:
sudo apt-get install python3-gi gir1.2-gtk-3.0
sudo apt-get install python3-gi-cairo python3-cairo
sudo apt-get install python3-setuptools python3-babel
sudo apt-get install fonts-font-awesome slop
如果使用 GNOME:
sudo apt-get install gir1.2-appindicator3-0.1
安装:
sudo apt-get install screenkey
手动通过源码安装
在GitLab页面 下载安装包
wget "https://github.com/wavexx/screenkey/archive/screenkey-0.9.tar.gz"
tar xvf screenkey-0.9.tar.gz
# 安装依赖
sudo apt-get install python-gtk2 python-setuptools python-setuptools-git python-distutils-extra
然后执行安装
sudo ./setup.py install
然后启动
screenkey
然后可以设置各种参数,延迟时间,字体,大小,颜色,透明度等等