fuchsia编译记录

本文主要参考自 https://fuchsia-china.com/guide-of-fuchsia-os-compilation/zh-cn/

我的开发环境是manjaro,基于archlinux,所以一些命令与ubuntu不同。

关于下载代码的相关说明

1. 由于fuchsia托管在google,所以下载很麻烦。开始使用electron-ssr作为http代理,但是这个软件经常会弹出提示框然后打断网络。因此建议使用cow做socks转http,可以比较稳定下载。

2. 由于使用了python2所以需要对/usr/bin/python的符号链接进行替换,指向python2

3. 由于脚本限制,代理服务器需要写成http://127.0.0.1:7777的形式,不然在python简本中会报错

4. 有时候出现ERROR: Project integration(integration) contains uncommited changes 可以删除那个文件夹然后重新执行jiri update 然后你会发现还报这个错误(我没找到解决方法。。。)

5. 截至目前(2019.3.4)fuchsia源码大小20G

下载后各目录大小

开始编译

编译很快,链接超级慢,不知道为什么连接时候根本没有并发,cpu基本空载,内存貌似没上过8,保险起见建议小于16g内存用户开启swap

编译开始

如果使用固态编译应该会快不少,由于硬盘都存电影了,只能找了个闲置笔记本硬盘还是usb3连接的,速度比较慢,从netdata可以看到明显的io等待,不过没办法,还有种子要下(手动滑稽),估计连接也是卡在io上了,于是电脑慢慢编译,我去睡觉了,明早再看结果把。

emmm,临睡觉前编译完了:)完了今天不能睡觉了

[feilong@feilong-dev fuchsia]$ time ./scripts/fx full-build
ninja: Entering directory `/mnt/fuchsia/fuchsia/out/build-zircon'
[13573/13573] STAMP obj/manifest-x64.stamp
ninja: Entering directory `/mnt/fuchsia/fuchsia/out/x64'
[1/1] Regenerating ninja files
[9326/9326] STAMP obj/build/gn/default.stamp

real    132m37.180s
user    186m42.420s
sys     15m26.925s

编译了好久

运行

我内存也比较多,所以也4g扔出去:)

后来看了下运行代码,默认2g,推荐-k 参数,启用kvm

kodi中python3调用you-get

最近打算把you-get放到kodi里面当一个视频插件,结果发现踩了好多坑。本来以为有现成函数可以直接调用,去搜了搜没找到,看了知乎这个https://www.zhihu.com/question/54939203问题,我表示服气的,高票教育一个小白去看文档。。。(然而根本没有开发文档可以看(小程序可以理解),文档里全是命令行用法,写程序根本没法用。费这时间要么你就直接告诉人家正确用法要么你就别回答,害得我找了那么久,不如直接说让我去直接看代码好了)底下还贴出几个代码,用os和sys.argv的,跟需求差得有点远,于是自己看代码。

上面纯属吐嘈。

目前kodi的版本为18,master分支仅支持python2,需要自行编译feature_python3分支。

将you-get封装成为kodi模块,或者可以直接安装我封装好的:)

https://github.com/feilongfl/script.module.you_get

安装后即可。

这里有一个坑,直接封装会出现这个错误

ERROR: EXCEPTION Thrown (PythonToCppException) : -->Python callback/script returned the following error<--
                                             - NOTE: IGNORING THIS CAN LEAD TO MEMORY LEAKS!
                                            Error Type: <class 'AttributeError'>
                                            Error Contents: 'xbmcout' object has no attribute 'buffer'
                                            Traceback (most recent call last):
                                              File "/home/feilong/.kodi/addons/plugin.youget/main.py", line 12, in <module>
                                                from resources.lib import plugin
                                              File "/home/feilong/.kodi/addons/plugin.youget/resources/lib/plugin.py", line 9, in <module>
                                                from you_get import common as youget
                                              File "/home/feilong/.kodi/addons/script.module.you_get/lib/you_get/common.py", line 22, in <module>
                                                sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')
                                            AttributeError: 'xbmcout' object has no attribute 'buffer'

因为在kodi中使用xbmcout没有buffer这个元素,实际用不到,注释掉就可以了

if sys.stdout.isatty():
    default_encoding = sys.stdout.encoding.lower()
else:
    default_encoding = locale.getpreferredencoding().lower()

这里也是同理,保留最后一行。

在kodi插件中添加

        <import addon="script.module.you_get" version="0.4.1193"/>

准备工作结束,于是终于到了调用you-get的时候。

总之先上代码吧,懒得看后面的可以直接抄走:)不过这部分代码仅仅是测试使用,所以只能播放一个视频,没有其他功能,只是展示下调用方法。

# -*- coding: utf-8 -*-

import routing
import logging
import xbmcaddon
import sys
from you_get import common as youget
from xbmcgui import ListItem
from xbmcplugin import addDirectoryItem, endOfDirectory
import xbmc


ADDON = xbmcaddon.Addon()
plugin = routing.Plugin()


@plugin.route('/')
def index():
    addDirectoryItem(plugin.handle, plugin.url_for(
        show_category, "one"), ListItem("Category One"), False)
    addDirectoryItem(plugin.handle, plugin.url_for(
        show_category, "two"), ListItem("Category Two"), True)
    endOfDirectory(plugin.handle)


@plugin.route('/category/<category_id>')
def show_category(category_id):
    runCmd([1,2])
    addDirectoryItem(
        plugin.handle, "", ListItem("Hello category %s!" % category_id))
    endOfDirectory(plugin.handle)

def download_urls(
    urls, title, ext, total_size, output_dir='.', refer=None, merge=True,
    faker=False, headers={}, **kwargs
):
    assert urls
    print(urls)
    playUrl(urls[0])
    return

def playUrl(video_url):
    playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
    playlist.clear()
    li = ListItem(path=video_url)
    li.setInfo( type="video", infoLabels={ "Path" : video_url } )
    playlist.add(url=video_url, listitem=li)
    xbmc.Player().play(playlist)

def test_main(**kwargs):
    youget.script_main(youget.any_download, youget.any_download_playlist, **kwargs)

def runCmd(command):
    extra = {}
    URLs = ['https://www.youtube.com/watch?v=AnwQAWmGgek']
    youget.set_socks_proxy("feilong-server.lan:10080")
    youget.download_urls = download_urls
    youget.download_main(
        youget.any_download, youget.any_download_playlist,
        URLs, False,
        output_dir='/tmp/', merge=True,
        info_only=False, json_output=False,
        **extra
    )

def run():
    plugin.run()

emmm,上面就是插件部分代码了。

主要调用部分是runCmd,因为最开始看了知乎的sys.argv,后来发现输出都在stdout里面,不想重定向于是看代码。

导入youget这个没什么好说的,看这名字,看看知乎,看看这体积,看看main函数就决定是common了:)

from you_get import common as youget

如果是在桌面环境下播放视频,确实是可以通过类似下面这种用法来运行。

    sys.argv=['you-get', 'https://www.youtube.com/watch?v=AnwQAWmGgek']
    youget.main()

但是在kodi中,需要拦截视频url并将其传递给kodi,由kodi解码播放。然而我看了看,貌似最后都在调用download_urls这个函数来下载视频,于是重载这个函数

def download_urls(
    urls, title, ext, total_size, output_dir='.', refer=None, merge=True,
    faker=False, headers={}, **kwargs
):
    assert urls
    print(urls)
    playUrl(urls[0])
    return
youget.download_urls = download_urls

然后调用这个

youget.download_main(
        youget.any_download, youget.any_download_playlist,
        # URLs, args.playlist,
        URLs, False,
        # output_dir=args.output_dir, merge=not args.no_merge,
        output_dir='/tmp/', merge=True,
        info_only=False, json_output=False,
        # password=args.password,
        **extra
    )

就可以播放了

顺便之前没有传递http的header,所以一些视频不能播放

def download_urls(
    urls, title, ext, total_size, output_dir='.', refer=None, merge=True,
    faker=False, headers={}, **kwargs
):
    assert urls
    print(urls)
    url = urls[0]
    for key, value in headers.items():
        print (key,' => ',value)
        url = "%s|%s='%s'" % (url,key,value)

    playUrl(url)
    return

添加进去就好了。

利用lz-string压缩数据,减少一半流量消耗

详情可参考lz-string官网,使用方法很简单,但是如果使用lz-string命令行压缩数据则有可能无法解压,建议选用utf-16

压缩脚本:

https://gist.github.com/feilongfl/f3ab5103e896ce5ee037ff3eaa002db8

var LZString = require('lz-string')
var fs = require('fs')

var filePath = process.argv[2]
console.log(filePath)
fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
    if (!err) {
        //console.log('received data: ' + data);
        fs.writeFile(filePath + '.lz', LZString.compressToUTF16(data), (err) => {
              if (err) throw err;
        });
    } else {
        console.log(err);
    }
});

node lzU16.js xxx.json

la xxx.json xxx.json.lz

压缩效果

feilong@feilong-server ~/i/pubrss> la comic.json*
-rw-r–r– 1 feilong feilong 156K 12月 22 23:28 comic.json
-rw-r–r– 1 feilong feilong 60K 12月 22 23:29 comic.json.lz
-rw-r–r– 1 feilong feilong 20K 12月 22 23:28 comic.json.xz

配置基于.lan域名的局域网https服务器

为了分配二级域名在内网,需要指定CNAME。

本地网络路由器是菲讯K2,刷潘多拉固件。

ssh登录,修改/etc/storage/dnsmasq/dnsmasq.conf

添加以下内容

https://gist.github.com/feilongfl/df38d9410a2a19ed9c430d01cbee907b

cname=f.lan,feilong-server.lan
cname=home.f.lan,feilong-server.lan
cname=huginn.f.lan,feilong-server.lan
cname=feilong.f.lan,feilong-server.lan
cname=server.f.lan,feilong-server.lan
cname=ttrss.f.lan,feilong-server.lan
cname=transmission.f.lan,feilong-server.lan
cname=bt.lan,feilong-server.lan
cname=status.f.lan,feilong-server.lan
cname=drive.f.lan,feilong-server.lan
cname=ipfs.f.lan,feilong-server.lan
cname=ipfs-api.f.lan,feilong-server.lan

由于潘多拉固件限制,需要手动将修改后的数据写入flash,执行

mtd_storage.sh save

服务器的主机名为feilong-server.lan,所以dnsmasq会自动分配该域名。

为了使二级域名正常工作,需要配置nginx代理。

在nginx.conf中http部分添加

include /etc/nginx/reverse-proxy.conf;
include /etc/nginx/reverse-proxy-https.conf;

证书存储于/ssl/server

自签证书gist: https://gist.github.com/feilongfl/713626c7ab3e82c3256d1fdf9889be2f

配置/etc/nginx/reverse-proxy.conf

server
{
    listen 80;
    server_name status.f.lan;

    rewrite ^(.*)$      https://$host$1 permanent;
    location / {
        proxy_redirect off;
        proxy_set_header host $host;
        proxy_set_header x-real-ip $remote_addr;
        proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:19999;
    }
    access_log /var/log/nginx/${host}_access.log;
}

执行https://gist.github.com/feilongfl/5738dd0127f6324ccbed6b06dcb60ceb生成对应https代码。

#!/usr/bin/env fish
mv /etc/nginx/reverse-proxy-https.conf /etc/nginx/reverse-proxy-https.conf.bak                                                                 
for l in (cat /etc/nginx/reverse-proxy.conf | grep -E '(server_name)|(proxy_pass)' | sed 'N;s/\n//' | sed -r 's/.*server_name (.*); +proxy_pass
(.*);/\1\t\2/g');
set h (echo $l | cut -f1)
set p (echo $l | cut -f2)
echo 'server {
    listen       443 ssl;
    server_name  '$h';
    ssl_certificate      /ssl/server.crt;
    ssl_certificate_key  /ssl/server.key;
    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;
    ssl_ciphers  HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers  on;
    location / {
            proxy_redirect off;
            proxy_set_header host $host;
            proxy_set_header x-real-ip $remote_addr;
            proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;                                                                       
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_pass '$p';
    }
    access_log  /var/log/nginx/'$h'_access.log;
    error_log   /var/log/nginx/'$h'_error.log;
}
' | tee -a /etc/nginx/reverse-proxy-https.conf
end
systemctl restart nginx

系统导入自签证书(参考https://www.archlinux.org/news/ca-certificates-update/)避免git/wget/curl/aria2/…出现证书错误,浏览器在浏览器中导入

sudo ln -s /ssl/rootCA.pem /etc/ca-certificates/trust-source/anchors/feilong.pem
sudo trust extract-compat

Nginx反向代理Huginn部分请求422

最近做了个ipfs的漫画网站,https://cimoc.netlify.com/。

由于基于ipfs,所以在访问时请求会被拦截到内网ipfs网关,由于内网网关在另一台电脑上于是需要配置证书来支持内网https。

配置证书和nginx反向代理后,发现在登录或其他设计POST操作时,HTTP返回422,网页报错。

查看官方指南:https://github.com/huginn/huginn/wiki/Nginx-reverse-proxy-configuration

发现配置缺少

proxy_set_header X-Forwarded-Proto $scheme;

添加后即可正常使用。

解决10min netdev budget ran outs警报

问题

在netdata监控中一直被报警10min netdev budget ran outs,查找softnet项。

原文

Statistics for CPUs SoftIRQs related to network receive work. Break down per CPU core can be found at CPU / softnet statistics. processed states the number of packets processed, dropped is the number packets dropped because the network device backlog was full (to fix them on Linux use sysctlto increase net.core.netdev_max_backlog), squeezed is the number of packets dropped because the network device budget ran out (to fix them on Linux use sysctl to increase net.core.netdev_budget and/or net.core.netdev_budget_usecs). More information about identifying and troubleshooting network driver related issues can be found at Red Hat Enterprise Linux Network Performance Tuning Guide.

机翻

与网络接收工作相关的CPU SoftIRQ的统计信息。 可以在CPU / softnet统计信息中找到每个CPU核心的细分。 处理状态处理的数据包数量,丢弃的数据包丢失是因为网络设备积压已满(要修复它们在Linux上使用sysctl增加net.core.netdev_max_backlog),挤压的是因为网络设备预算而丢弃的数据包数量 用完(在Linux上修复它们使用sysctl来增加net.core.netdev_budget和/或net.core.netdev_budget_usecs)。 有关识别和排除网络驱动程序相关问题的更多信息,请参阅“红帽企业Linux网络性能调整指南”。

解决方法

执行以下命令:

sysctl net.core.netdev_max_backlog
sysctl net.core.netdev_budget

提示

net.core.netdev_max_backlog = 1000
net.core.netdev_budget = 300

这两个默认值很小,由于本人不了解tcp底层原理,只能依照说明调大这两个值。

sudo sysctl net.core.netdev_max_backlog=10000
sudo sysctl net.core.netdev_budget=3000

同时,根据说明调整

sudo sysctl net.core.netdev_budget_usecs=20000

调整过后,softnet蓝线减小为零,十分钟左右后消失,警报也随之消失。

screenshot-2018-12-08-at-17-41-38-e1544262219996.png

如果是在路由器或其他低功耗设备中sysctl命令可能有busybox提供,设置时需要-w参数

但是,重启后会失效,将上述参数保存至/etc/sysctl.conf