寻找技术上既能规避自家网络使用 BT 协议又能利用本地环境的大硬盘的解决方案
Wireguard + Transmission
以前一直使用 docker-transmission-openvpn 这个 repo 的 OpenVPN
但是
使用 linuxserver/wireguard
镜像启动 wireguard 并在镜像内安装 transmission
1 | version: '2.4' |
在 wg0.conf
中添加 PostUp / PreDown 脚本启动 Transmission
1 | [Interface] |
1 | s6-setuidgid abc transmission-daemon -f & |
1 | echo "Stopping transmission..." |
启动做种之后在各大 PT 站发现自己只有 IPv6 权限,然而在容器内可以 ping 通 IPv4 地址(从延迟上来看也确实走了 VPN)
而在VPN服务器上同样也安装了 Transmission 客户端,但是却正常显示双栈权限
Google 中搜索过后大多数的解决方案是添加一行 precedence ::ffff:0:0/96 100
到 /etc/gai.conf
文件中
但尝试之后并没有起到有效作用,于是常识在 wg0.conf
中不分配 IPv6 地址后拥有 IPv4 权限,一度尝试放弃准备起两个容器一个走 v4 一个走 v6
再次更换搜索词为 “双栈 transmission” 后,出现了一些结果,发现写到
需要通过更改 host 或者调整系统前缀策略让 BT 客户端通过 v4 连接 tracker
设置双栈做种时,先在本机网络适配器中关闭IPV6协议,然后ping一下tracker服务器,得到一个IPV4地址,将这个IPV4地址和tracker服务器域名写进系统的hosts文件,再开启IPV6协议即可。
这才醒悟到根本原因很有可能是 transmission 汇报的ip地址为网卡地址,种子服务器接收后不认可私网IPv4地址,于是开始屏蔽汇报服务器的AAAA地址
custom-cont-init.d
下新建安装启动 bind9 脚本
1 |
|
创建 named.conf
挂载进容器喂给 bind9
1 | plugin query "/usr/lib/x86_64-linux-gnu/bind/filter-aaaa.so" { |
容器挂载
1 | # ...前略 |
后正常拥有双栈权限
发现交换客户端中永远没有 IPv6 地址后,遂尝试 ping IPv6地址,无果,traceroute 之后发现停留在 VPN 服务器上不到达 container
Ubuntu 上 apt -y install ndppd
创建
1 | # eno0 is your NIC name like eth0 etc... |
运行 service ndppd restart
就可以了。
双栈做种
双栈环境挂 PT 需注意
关于IPv6的常识科普,以及VPS通过ndppd向母鸡广播小鸡内网IPv6邻居的方法教程
其实搭建这个东西是 2021 年做的事情了,当时这个东西还挂在群晖上还解决了 wireguard 代理 IPv6 路由表的奇怪问题,但现在回想整个过程,其实是对网络部分,与操作系统这边的实现细节并不清楚才会走了很多弯路,回想发生过有很多类似的事情,不刨根问底就会有“感觉上对这个东西应该很熟悉每天都在打交道”但为什么最后会有偏差的问题
另外整体一遍做过之后调试之后也对 IPv4 / IPv6 有了进一步的认识,对网络问题如何定位,查找也有了一些心得。
终于可以把 2021 年的 Chrome Tab 给关上了呢
package.json
和 packagE.json
。这个细节很小,因为大家不是英语母语,现在又越来越依靠 intelliSense 补全文件路径,在这个事情上翻跟头会比较少,就算翻了跟头也很容易忘记。
大多数情况下你在这个上边会跌进的一个坑是
也许是之前哪位高人用记事本写的代码
1 | const list = require('./List'); |
然鹅现实生活中你的 List 的文件名是list.js
完了,你就得在你的代码库里把 List 统统改成 list
所以这其实是个很小的问题也很容易解决就是浪费了一点时间。
但我碰到一个浪费了我一个下午的问题,也促使我写了这篇其实没有什么技术含量的笔记
require('./a.js') !== require('./A.js')
前因后果:
在用 TypeORM 写增删改查的时候,新引进了一张表,于是挂上去调试。发现一直报找不到表的错
1 | TypeORM EntityMetadataNotFound: No metadata for "***" was found |
就是这个错。
反反复复确认了表已经挂到了 option 下边。
怎么办,只能进 node_modules 下边直接改源码调试了(
进去 console.log
三下五除二,发现表确实挂载了,然而
https://github.com/typeorm/typeorm/blob/master/src/connection/Connection.ts
1 | /** |
1 | /** |
左边右边都是 Function xxx,但是却不完全相等。
于是我开始疯狂比较两边 import 的代码,最后才发现,import 的时候因为 Class 名和文件名一样,所以一个用的是 intelliSense 自动补全,一个是我复制粘贴的 Class 名,但是 Class 名是首字母大写的,但文件名不是。
那么为什么同样的文件,引用的时候文件名不同,引用会不同呢?
https://github.com/nodejs/node/blob/master/lib/internal/modules/cjs/loader.js#L936
我们都知道 Node.js 的 require 只会引用一次,究其原因是因为 Node.js 会把模块缓存到内存里,以便快速重复调用。
我们在上边的源代码可以看到,Node.js 会使用 filename 进行缓存,而这里的 filename 是你 require 的文件名 + 绝对路径。
因此 Node.js 会认为这是两个模块,就会重复 require 两次,但是如果是在 windows 下,filename 会被 path.resolve 给 toLowerCase 成一个模块,在 Linux 下,又会因为大小写敏感而找不到模块,也就是只会在 macOS 上出现的一个问题。
所幸不是到部署才发现的问题,也所幸这个只会在调试的时候出现问题。。。。
]]>package.json
と packagE.json
は一緒にいられない。ほとんどの人は知ってるかにもかかわらず、あまりこれに注意を払ってないのではないかなと思って、だってみんなの母語は英語ではないし、インポートの際は intelliSense も結構賢く補足してもらってるので、あんまりここに転んだことはないと思います。転んでもすぐ忘れるんだろう。
よく会った問題はこれです👇
多分誰がメモ帳で書いたコード
1 | const list = require('./List'); |
でも List のファイル名はlist.js
、
そしたらすべての List を list に変えなきゃいけない。
細かい点で解決には難しくないが、時間ちょっと無駄しましたね。
でも今日話したいのは僕の午後をまるごと無駄しましてこの技術的な内容あまりない記事を書くことになったこれです👇
require('./a.js') !== require('./A.js')
TypeORM を使ってる時新しいスキーマ(テーブル)を入れたが、デバッグの時ずーとそのスキーマが見つからないエラーに怒られて
1 | TypeORM EntityMetadataNotFound: No metadata for "***" was found |
option に何度も確認しまして確かにスキーマは入ってるが。
どうしようと思って、 node_modules に入って直接ソースコードを改ざんしてデバッグすることになった。
console.log
でスキーマはたしかに入ってますが、
https://github.com/typeorm/typeorm/blob/master/src/connection/Connection.ts
1 | /** |
1 | /** |
左と右は同じく Function xxx
がリファレンスは同じではない。
これは事件ですね。んでファイル両方の import を一行一行で確認して、最終的に import のパスに問題を見つかった。
自分がインポートした際に、一つは Class 名をそのままコピペしたが、もう一つはファイル名でしたが、Class 名は PascalCase が、ファイル名は camelCase でした。
そしたらなぜ同じファイルで使う時ファイル名が違ったらリファレンスは違うになりますか?
Node.js のソースコードに見てきました。
https://github.com/nodejs/node/blob/master/lib/internal/modules/cjs/loader.js#L936
Node.js の require は一回しか実行しない、その原因は Node.js はモジュールをメモリに保存して、その後コードの中で require したらすぐ使えるという意図で設計されました。
ソースコードからも見えて、Node.js はファイル名でキャッシュしますが、ここの filename は require のファイル名 + 絶対パス。
なので Node.js は2つモジュールとみなすが、windows だと、 filename は path.resolve で toLowerCase で同じファイル名にするが、Linux だとケースセンシティブでモジュール見つからないで弾かれますが、この問題は macOS しか出ませんね。
ま、デプロイまで問題出るよりラッキーですね。
]]>无论是在浏览器,还是在服务端 Node.js,我们经常会碰到打点上报,追踪错误这样的需求,即使不对特定用户进行追踪,我们也会给某个 session 分配唯一 ID 以在 log / analytics 界面能够看到用户的完整行为,对于产品分析与错误再现是十分重要的。
假设我们需要写一个 error handling ,这个 error handling 会 hold 住所有的请求的异常,我们如何分辨哪个错误是哪个请求造成的呢?
1 | log.error("Error occured", req); |
那么这个 error handling 就跟 req 耦合了
假设我们需要追踪某个错误,是哪个 user 产生的,又或者是哪个错误,user 干了什么导致的?
1 | log.info("User has done xxx", user); |
于是跟 user 也深深的耦合了。
单单这样的例子好像没有什么大问题,不过多两个参数嘛。但写过大型应用的同学,后期不断增加功能的时候,你一定写过那种长长的参数列表的函数,又或者是好几百行的一个函数,实在是太不优雅,重构起来也太难。
函数如果是同步的,那么我们可以直接挂到全局变量(某个对象)下
1 | const global = {}; |
显然这在异步中行不通
1 | const global = {}; |
你会发现打印的 global.event 全变成了同一个对象
我们需要能够从始至终在同一个异步调用链中一个持续化的存储,
又或者是我们需要能够辨识当前的异步函数他的唯一辨识符,以和同样内容的异步函数但并不是本身的运行的这个作区分。
在其他语言中,有一个叫做 Thread-local storage 的东西,然而在 Javascript 中,并不存在多线程这种概念(相对而言,Web Worker 等与主进程并不冲突),于是 CLS ,Continuation-local Storage,一个类似于 TLS,得名于函数式编程中的 Continuation-passing style,旨在链式函数调用过程中维护一个持久的数据。
先看看是怎么解决的
1 | $('button').click(event => { |
Zone.js
是 Angular 2.0 引入的,当然它的功能不只是提供 CLS,他还有其他相关 API。
我们试着思考一下, Zone.js
是如何做到这些的。如果浏览器没有提供异步函数运行环境的唯一标识,那么只剩下唯一的一条路,改写所有会产生异步的函数,包装了一层后也就能加入hook了。
我尝试自己写了一下
看似好像没什么问题,不过
angular with tsconfig target ES2017 async/await will not work with zone.js
我们可以做个实验,在 console 里敲下如下代码
1 | const _promise = Promise; |
也就是说浏览器会把 async 函数的返回值用原生 Promise 包装一层,因为是原生语法,也就无法 hook async 函数。
当然我们可以用 transpiler 把 async 函数改写成 generator 或者 Promise,不过这并不代表是完美的。
Node.js 8后出现的 async_hook
模块,到了版本14仍然没有移去他身上的 Experimental
状态。以及在刚出现的时候是有性能问题的讨论(3年后的今天虽然不知道性能怎么样,不过既然没有移去 Experimental
的标签,如果追求高性能的话还是应该保持观望)
虽然没有移去 Experimental 的状态,但是稳定性应该没有什么太大问题,大量的 Node.js 的追踪库 / APM 依赖着 async_hooks 模块,如果有重大问题,应该会及时上报并修复
对于性能问题,不展开篇幅讨论,取决于你是否愿意花一点点的性能下降来换取代码的低耦合。
async_hooks 提供了一个 createHook 的函数,他可以帮助你监听异步函数的运行时创建以及退出等状态,并且附带了这个运行时的唯一辨识id,我们可以简单地用它来创建一个 CLS。
在社区中已经有了那么多优秀实现的前提下,Node.js 13.10 后新增了一个 AsyncLocalStorage
的 API
https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage
实际上他已经是开箱可用的 CLS 了
1 | const { |
ブラウザか、サーバーのNode.jsか、どっちでもエラーハンドリング、ユーザートラッキングのニーズは日常茶飯事。例えユーザーを特定しなくても、id をつけて、ユーザーの行為を追跡して、エラーの再現にも重要し、プロダクトの改善にも役たちます。
仮に今エラーハンドリングを書こうと思って、このエラーハンドリングはすべてのエラーを処理しますが、どのリクエストから生み出したエラーを知りたいと
1 | log.error("Error occured", req); |
このハンドリングは req と結合しちゃった
仮に今このエラーどのユーザーから出たエラー、ユーザーが何をやったかを知りたいと
1 | log.info("User has done xxx", user); |
ユーザーとも結合しちゃった
この2つの例は一見するとそんなに大きいな問題ではなさそう、ただ2つのパラメータが増えただけじゃ。
だけど、大型サービスを作る時、どんどん増えた機能に対して、関数の引数と関数の長さと共にどんどん伸びちゃって気持ち悪くてリファクタリングしようとしょうもないこと、少なくありませんでしょうか?
関数が同期のであれば、グローバルで変数につけたらいいじゃんー
1 | const global = {}; |
だが、非同期関数のであれば
1 | const global = {}; |
すべての global.event は同じイベントになちゃった(´;ω;`)!それはだめですね。
我々必要なのは非同期呼び出しチェーンに最初から最後まで持続的なストレージ、
もしくは今走ってる非同期関数の呼び出しの唯一の識別子。
他の言語では、Thread-local storageと呼ばれるものがあります。が JavaScript はマルチスレッドはありません(Web Workerなどはメインと関係ないし、自分でもマルチスレッドしない)。CLS という名前は TLS みたいに関数型プログラミングからの Continuation-passing style 名前をもらって、Continuation-local Storage、そのチェインの呼び出しの中で持続的データストレージをメンテナンスする。
どうのように解決したかちょっと見てみましょう
1 | $('button').click(event => { |
Zone.js
は Angular 2.0 から誕生したもので、もちろん他の機能も持ってる。
考えてみましょう、 Zone.js
はどうやってこれを実現しました。ブラウザは呼び出しに対して唯一の識別子を提供するAPIがなければ、すべての非同期関数をリライトしかできなく、そうすれば非同期が入る時と出る時 hook できて、この効果が実装できますね。
自分も書いてみました。
また問題なさそうだけど、
angular with tsconfig target ES2017 async/await will not work with zone.js
実験をやってみましょう、console で下のコードを打ったら、
1 | const _promise = Promise; |
ブラウザは、async 関数のリターンをネイティブの Promise で再ラッピングします。ネイティブ文法なので、async 関数はリライトできない。
もちろん transpiler で async 関数を generator もしくは Promise にすることは可能ですが、完璧とは言わないでしょう。
async_hooks
Node.js バージョン 8 以降出た async_hook
モジュール、バージョン 14 の今でも Experimental
ステータスから脱却してない。出たごろ性能に関しての議論もあったが、今はどうなってるかまだわからない状態ですが
Experimental ステータスにしても安定性としては問題なさそう、大量な Node.js のトラッキング / APM が依存していて、問題があったら issue が立てられるはずです。
性能に関する問題はここは展開しない、コードの低結合と少しパフォーマンスの低下を交換するかしないかによりますね。
async_hooks
は createHook
という関数を提供した、これが非同期関数のライフサイクルに hook できます、しかも唯一識別子も提供してくれますので、CLS を簡単に作れます。
コミュニティの中でたくさんの CLS ライブラリーがあった上に、Node.js 13.10 から AsyncLocalStorage
の API がありました。
https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage
実はこれはすでにすぐに使える CLS です。
1 | const { |
一句话概括就是 Cloud Function + Object Storage + Cloud Database + API Gateway and more by Cloud Service Provider. 简单来说就是有个叫 serverless 的开源框架把云厂商提供的这些服务整合成了一个配置文件,后端运维统统都不要了。好处显而易见,服务弹性伸缩,价格按量收费,大多数的运维问题,你的云服务提供商统统帮你兜了,小学生也能写网站。
这么牛逼,前端可得好好学学,让后端和运维统统下岗咯?
既然 Serverless 图的就是快,那我们自然是不能自己手动一个一个的去到云服务商那里去手动设置的咯。
当然你也可以这么做,只不过我的服务今天就上线,你的服务可能就要等到后天了。
Github 星星 3万个,1000万下载的 serverless npm package,npm install -g serverless
,下载!启动!
任意位置,terminal 输入
1 | $ serverless |
友好向导一步一步带你迈向 serverless 美好大坑
进入你刚创建的项目,敲下
1 | $ sls deploy |
点击屏幕给出的连接!
1 | Hello World! |
牛逼!我们的后端服务器已经搭好了!太简单了吧!
国内用户 serverless 自动使用腾讯云
以上内容其实在 https://www.serverless.com/framework/docs/providers/aws/examples/hello-world/node/ 都有
以下内容使用 aws 进行操作
今天我打算做一个信用卡外汇比价工具,三步搞定:
非常适合 serverless 的初学应用
代码已经开源并上线,欢迎大家边看边 review
成品地址:https://whichcard.xingoxu.com/
代码地址:https://github.com/xingoxu/whichcard-abroad
serverless 这个框架,还能使用 template 来创建项目,既然图的就是快,找一个现成的模板套进去,填一填就上线是不是更美滋滋
技术栈,就选 nuxt.js,开启 SSR,再加上可编程使用,妙啊
搜一搜
1 | serverless create --template-url https://github.com/tonyfromundefined/nuxt-serverless -n whichcard-abroad |
创建项目后,我们编辑一下 serverless.yml
,加上非关系型数据库相关配置
1 | resources: |
数据库需要配置权限,要给运行 lambda function 的用户,也就是第一次使用 serverless 的时候让你发行的那个key所代表的用户,给他权限,那,同样在 serverless.yml
下加入
1 | provider: |
好了,我们服务器已经配置完了,开始编写后端
刚才用的这个模板,大多数已经搭建好了,只不过后端这里没有 typescript 支持
tsconfig.json
复制一份,重命名 tsconfig-server.json
配置我就不粘过来了,大家可以自己参考上边连接。
用了 typescript 之后,我得把他变成 js 后才能被 lambda function 给读取,在 webpack.config.js
加上 ts-loader
。
我们导入 axios
,导入cheerio
,三下五除二,jQuery一把梭,轻松加愉快,摸出了他的汇率
1 | import axios from 'axios'; |
40行的代码我们就解决了战斗
既然按需付费,那么空闲的时候云厂商势必不可能给你资源,因此云函数是无状态这点其实还是比较 make sense 的
虽然我们可以对每个请求都实时抓取一次汇率,但是这显然也太影响打开速度、用户体验了吧。
而且如果被上游发现,对方直接把 aws 一整段 ip 给封了的事情也不是没有
即使是抓取公开数据这种事情,还是静悄悄搞比较好。
直接导入 aws-sdk
,草草几行代码就能写好保存工具函数和查询工具函数
1 | import { DynamoDB } from 'aws-sdk'; |
DyanmodbRequestAdapter
和DyanmodbResultAdapter
是为了解决 dyanmodb 存储的时候符合他的sdk的递归的key(加上类型),另外在这里篇幅过长略去了一些类型定义,大家可以在源代码里查看
同时,我们不要忘记,数据在抓取/存储的过程中都有可能发生新请求,因此我们再写一个工具类把刚才的抓取函数包装一下
1 | export function asyncOnce< |
其实我们这个网站,如果没有关于帮助页面的话,就是只有一个页面的网站了。因此其实没有必要暴露 API,不过我这次为了尝试一下Nuxt.js的Programming Usage,那前端和后端就可以非常巧妙的结合在一起
我们直接在 SFC 中 import 进我们刚才写好的抓取函数
1 | import { response } from '@/api/functions/currency'; |
这样的话,就算是 SSR,也不需要自己向自己发送一个 /currency
的请求。
如果我们没有其他页面,那么 /currency
的API也不用暴露,相当于把 Nuxt.js 当成了模板引擎!
写过 Express.js 等的小伙伴很清楚,一般是先生成数据,然后渲染模板,但是在这里,我们的重点是先写好前端后,导入 server 的函数,把请求丢过去拿数据。
是不是很野!(此处应该有惊叹声(哇哦好野))
剩下的写界面啊,写排序啊什么的就略过。
Nuxt.js 默认不开启 extractCSS
,如果你像我一样引了一个 UI 库,还对这个 UI 库自定义了的话,那你的 HTML 可能会长到令人发指。记得在 nuxt.config.js
中启用哦
我暂时还没有深入去看是 Nuxt.js 的 webpack 的问题,还是可能是 vue-loader
的问题(毕竟我们的宗旨是要快)
不过这个问题可以用 nuxt plugin 的方式去回避。
在 plguins
文件夹下创建 getData.server.ts
,
把跟 server 有关的写成一个 handler,然后挂载到 Vue
上也可以,context
上也可以,都可以,只要是个在 SFC 中可以访问到的全局方法就可以了。
1 | import Vue from 'vue'; |
然后到 SFC 里把刚才 Server 的方法改成这个全局方法
1 | if (process.server && context) { |
另外 ts 定义的问题,在函数的旁边 declare 一下就没有问题了(源代码)
记得参考 Nuxt.js Plugins & Vue.js Augumenting Types for Use With Plugins
Serverless 本身其实并不是什么新鲜东西,云函数运行环境、对象存储、云数据库哪个都不是2019年或者2020年才出现的新东西,但他的想法解决了小微服务的上线速度问题,对刚起步的成长型企业,没有基础设施的小公司,或者是我有一个想法就差一个程序员的公司来说,是一个非常省时间省事情节约人力物力成本的选择。
不过…
就问你怕不怕本地跑得好好的,放到云厂商那边炸了,然后调试无门!
为什么会这样呢,我们以 aws 为例,你有没有想过云原生是怎么处理 node_modules 这样的问题的?
答案是,和你的源代码一起上传!
🐂🍺了我的 aws,也就是说如果你的 node_modules 里边有依赖 native 能力的话,传上去必爆炸,而且你本地还检测不出任何问题。
云服务商又当基础服务提供商,又帮你干了运维 Scaling 的事情,还提供了友好的 Interface ,这么多这么好的事情,当然不可能是免费的,一年免费与看起来低价的 lambda 的背后,是高额的捆绑消费以及对价格不敏感群体的整体割韭菜
我没有办法直接对比使用 Serverless 的开销与传统服务器的开销,但是 以AWS 为例,Serverless 使用的 API Gateway 每百万次 $3.5 请求对于一个正常企业来说,应该是不小的开销,甚至如果遭受一次 DDNS 攻击的话,确实是有点害怕你的房子明天是不是还在了。。。
而相比之下只需要多花几刀钱买一个不错的云服务器,独享内存,相对稳定的CPU,以及几乎无限流量(Fair Use),显而易见应该是一个更省钱的选择。
在大公司里有着自己的基础设置,运营着自己的云原生,那么适当的下放一些简单的增删改查需求给前端,效率提升应该是毋庸置疑的。
以上,希望本文的整体思想,又或者是代码片段,能够给你带来一些灵感或者启发。
本文有任何问题欢迎指出,也欢迎你对我写的这个小学生网站提出任何意见。
欢迎给本文打赏(在线要饭)
]]>一言いうと Cloud Function + Object Storage + Cloud Database + API Gateway and more by Cloud Service Provider. 簡単にいうと Serverless というとある OSS フレームワークが AWS/Azure/GCP などクラウドサービスを一つの設定ファイルにまとめて、バックエンドもいらずサーバーを立てる。
メリットとしては:
肝心のロジックだけ集中する必要なので小学生でもサービスを爆速で作れる時代に入ったかも?
そんなにすごいならみんな覚えたらサーバーエンジニアの職がなくなったんじゃ!
以下、AWS を例として使います
爆速を言いまくったので、AWS で一つ一つ設定するわけがない。もちろんそうやっても問題ありませんが、今日俺のサービスを作って発表しますが、君のサービスは後日まで待たなきゃよ。
Github Star 3万個、一千万ダウンロード数の serverless npm package、npm i -g serverless
でインストール、そして、ターミナルでこれを打つだけ
1 | $ serverless |
チュートリアルが出てきてお手軽に環境構築を手助けしますね。
そして、作ったプロジェクトのフォルダーに入って、
1 | $ sls deploy |
出てきたリンクをクリックして、
1 | Hello World! |
すっげぇじゃん、もうサーバー立てましたじゃん!
今日僕は https://whichcard.xingoxu.com/ このサイトを作ります。
何かというと、海外カードを使う時ポイント+手数料がどのカードが一番お得なのがわかんないので、ランキングがあるとわかりやすくと思って作ったわけ。
そして、これを作るために、たった三つのステップ。
Serverless の実践としては最適と思いますね。
ソースコードはアップロードしましたので、そちらを見ながらレビューしていただけると大歓迎です。
んで、検索したら意外と Serverless のテンプレートに Nuxt.js もありますね!
テンプレートを使ったら更に開発スピードを加速しよう、いいっすね~
1 | serverless create --template-url https://github.com/tonyfromundefined/nuxt-serverless -n whichcard-abroad |
作ったら、serverless.yml
を編集します。Non-relation Database周りの設定をします。
1 | resources: |
データベースに権限を与えないとはいけないので、lambda function を走ってるユーザー、すなわち serverless を叩くときに key を発行されたユーザーに権限を与えますので、serverless.yml
の中にこれを加えよう
1 | provider: |
はいサーバー設定終了🙌おめでとう
次は、バックエンドのTypeScriptを追加します
このテンプレートはバックエンド全部設定してくれましたが、バックエンドのTypeScriptは追加してないので、
tsconfig.json
をコピーして、tsconfig-server.json
に変更します。
内容もちょっと変わりましたが、ここに貼らなく上のリンクに見に行っていただけると🙏。
TypeScript追加したら js にコンパイルしなきゃ node.js の lambda function には使えないので webpack.config.js
にts-loader
の追加をお忘れなく。
axios
とcheerio
を導入して、jQuery感で40行のコードで楽に為替を取ってきました
1 | import axios from 'axios'; |
従量制課金なので、空いている時はリソースは配られるわけがない、なのでCloud Functionは無ステータスは筋が通っている。
一つのリクエストに対して、為替を取ってくるのは問題ないが、ユーザーエクスペリエンスとしては最低でした…
しかも、データが取られたサイトに見つかられたら、AWSのIP全部ブロックすると一番やばい。パブリックデータとしても、少しモラルがある方法で取るほうがいい。
aws-sdk
をインポートして、TypeScriptではちょっと転換面では面倒(型定義では少しコード増やさなきゃ)だけど、基本的には時間かかってないと気がする。
1 | import { DynamoDB } from 'aws-sdk'; |
DyanmodbRequestAdapter
とDyanmodbResultAdapter
は aws-sdk を使うためにデータの転換関数。長いのでここで貼らなく、ソースコード見ていただけると思います。
データを取る時と保存する時リクエストが来る可能性もありますので、asyncOnce
の関数を書いて入り口をラッピングして一回だけ実行させることを保証しましょう。
1 | export function asyncOnce< |
さっきも言ったけど、Nuxt.js の Programmatically で使えるのは重要。なぜ重要というと、Cloud Function の入り口は一つで、リクエスト来る時フロントエンドのレンダリングとAPIのサービングは両方立たなきゃ。
従来のやり方としては、Express.js
などでRouterを追加して、静的HTMLをレンダリングする、いわゆるサーバーレンダリング。
それだとフロントエンドエンジニアにとってはちょっと不便、でもこれを使ったら、サーバーとフロントが賢く纏まった。
ちょっと見てみましょう
SFC でさっき書いたサーバー関数を import します
1 | import { response } from '@/api/functions/currency'; |
そしたら、SSR の場合はサーバー自身が自身の /currency
にリクエストすることはなくなりました。
また、この設計のいいところは、もしほかのページがなければ、/currency
の API も外に出さなくてもいいです、Nuxt.js をテンプレートエンジンとして使った。
Node.js をサーバーとして使った方はわかると思います、普通のサーバーレンダリングはデータ生成してからレンダリングするが、ここではフロントエンドを先に書いちゃって、その後サーバーの関数をインポートして、データを取る。
書き心地もわかりやすい。
すごくない?
残りはインターフェイスなどは、ここでは略します。
Nuxt.js はデフォルトとしては extractCSS
を閉じてます、UI Frameworkを使った方はもしかしてHTMLはとんでもない長さにされました。nuxt.config.js
にての起用をお忘れなく。
Nuxt.js の webpackか、vue-loader
かどっちの問題まだ深く見てないが(爆速で作るわけ)、nuxt plugin で迂回することはできる。
plguins
フォルダ下に getData.server.ts
を作ります、
サーバー関数をhandlerにして、Vue
でもいいし、context
でもいいし SFC でアクセスできるグローバル関数であればOK。
1 | import Vue from 'vue'; |
SFCでさっきのところでこの関数を使う
1 | if (process.server && context) { |
TypeScriptの型定義なら、その関数の隣で declare すればどこでも問題ないはずです(ソースコード)
レファレンス Nuxt.js Plugins & Vue.js Augumenting Types for Use With Plugins
Serverless は新しいものではない、Cloud Function、Object Storage、Cloud Database どっちでも2020年から出たものではない。ただそのコンセプトはスタートアップ企業のサービスのラウンチスピードをすごく手助けしました。彼達にとって、サーバーさえもないし、エンジニアもわずか数人もしくは一人だけかもしれませんが、そんな状況の企業にはとてもふさわしいも過言ではない。時間とコスト両方省けられる選択です。
でもね…
「あら、ローカルでちゃんと動いてるのに、アップロードしたらエラーが出ちゃった!」
それはなぜですか?AWS を例としてCloud Native はどう node_modules を処理してるのは見てみましょう。
その答えは、コードと一緒にアップロードします。
つまり、node_modulesにnode-gypなど native を依存してるかつ aws のハードウェア適してない場合は必ずエラーが出るのではないか、しかもローカルでは検知できない。
さっきまだコストを省けると言ったのに、それなぜまた問題と視されますか?
クラウドサービスプラットフォーム、ベーシックサービスを提供しながら、インフラ、自動スケーリング、フレンドリーインターフェイスも提供し、そんなにいいこと無料のわけがない。最初に一年無料、従量制課金の後ろは、他のサービスを同梱して一緒に課金しちゃうと、価格に対して敏感ではない人を「騙す」
Serverless と従来のサーバーを直接で比較することはできない、ただ、AWS の API Gateway 百万回 $3.5の料金は高くない?DDNSを受けたら、お家飛んできそうよ。
$5では vultr 買えます、しかも無限トラフィック、安定してるリソース、サービスがでかくなったらコスト的には絶対勝つと思います。
AWS でサービスを立ったが、後日 AWS と揉めたら、また Amazon と利益上で対立して他のクラウドサービスに行きたい、もしくは自分のサーバーがありまして自分のサーバーに移行しようとすると、コードをもう一度書かなきゃし、設定とか見直さないとも行けないし…
もしでかい会社のであれば、自分がそのインフラ持ってて、Serverless みたいのものを作ったら、適当に簡単なものをフロントエンド側に任せたら効率的にはすごく早いのではないかと考えられますね。
ご閲覧ありがとうございました、この記事の考え、コード、あなたにアイデアまたはインスピレーションをもたらしたら嬉しいです。
記事について質問、またはこの小学生も作れるウェブサイトについて意見があれば大歓迎です。
]]>npm i puppeteer-firefox
Same-Site=LAX
Chrome 正在开发的
关联Session: What’s New with Chrome and the Web (Google I/O ’19)
开发中
很快实装
以上内容年内实装
在 Chrome 中可参与试用并参与反馈
https://developers.chrome.com/origintrials
Web API 可在 Project hugu 参阅进度 Project hugu
相关Session: Unlocking New Capabilities for the Web (Google I/O ’19)
关联Session: What’s new in JavaScript (Google I/O ’19)
Chrome 想为各个框架提供一些API这样他们在连续执行分块任务时同时相应用户输入
Google 分享了他们在性能上的一些做法和建议
Google 的性能建议
以及使用Lighthouse 与设定性能预算 LightWallet
相关Session:
Elevating the Web Platform with the JavaScript Framework Community (Google I/O ’19)
Speed at Scale: Web Performance Tips and Tricks from the Trenches (Google I/O ’19)
更多性能其他案例、How to、以及Web内容可参照
https://www.youtube.com/playlist?list=PLNYkxOF6rcIATmAmz7HcCzongGvQEtx8i
npm i puppeteer-firefox
Same-Site=LAX
を適用するChrome今開発中もの
関連Session: What’s New with Chrome and the Web (Google I/O ’19)
独自APIを開発するから海外でも好評得ていないらしい…
開発中
もうすぐ実装します
上記内容年内実装
Chrome で試すまたフィードバックは下記サイトまで
https://developers.chrome.com/origintrials
Web API は Project huguで 確認できます Project hugu
関連Session: Unlocking New Capabilities for the Web (Google I/O ’19)
関連Session: What’s new in JavaScript (Google I/O ’19)
Chrome はフレームワークなどスケジュールAPIを提供したい、
連続実行、レンダリングの時もユーザーの操作受けるように。
Google はパフォーマンスにやり方とアドバイス
Google のパフォーマンスアドバイス
また、Lighthouse を使って、性能予算を設定する
関連Session:
Elevating the Web Platform with the JavaScript Framework Community (Google I/O ’19)
Speed at Scale: Web Performance Tips and Tricks from the Trenches (Google I/O ’19)
他のパフォーマンスユースケース、ノウハウ、Web内容はここへ
https://www.youtube.com/playlist?list=PLNYkxOF6rcIATmAmz7HcCzongGvQEtx8i
录像服务器就是指将电脑接上电视天线,把电视节目自动录制下来并保存在硬盘上。在日本许多电视机都会自带录制功能,指定节目之后每周录制相同时间段的节目,或者指定条件,自动录制符合条件的节目。这次我们就要来尝试在NAS上搭建这么一个录制服务器。
既然电视机已经有了这样的功能,为什么还需要额外搭建这样的服务器呢。
电视机确实已经很强大,但我们也有串流需求,在家,在外边,在笔记本上随时随地都想收看录制的电视节目的话,只有一个电视机和收看设备的话很难做到。
搭建了这个服务器之后,我们还能实现在手机在电脑实时观看电视直播功能,画质当然与电视台一致。
还不是为了拯救我那24小时开机的NAS但却只用来同步文件的电老虎吗
以下内容仅保证文章撰写时点的有效性,本文并不面向初级用户,请仅有一定动手能力以及自己能够解决途中出现的问题的读者进行搭建,并请自行负担出现的任何问题与责任。
电视节目的复制,传播可能触及相关法律,在使用时请十分注意。
由于参考了本文进行的操作发生的任何损失,作者不负担任何责任与赔偿。
进入Ubuntu虚拟机,安装天线驱动,具体操作步骤:
1 | $ wget http://plex-net.co.jp/plex/px-s1ud/PX-S1UD_driver_Ver.1.0.1.zip |
就算完成了
因为天线驱动最低支持3.15的Linux内核,而群晖的内核是3.10,导致没有办法将天线与调用天线驱动的内容放置在主机本体运行,才不得不使用了虚拟机这样的结构。
如果群晖之后升级到了3.15以上的内核,那可以尝试一下使用 https://github.com/Chinachu/docker-mirakurun-chinachu 的 Docker 镜像。
在Ubuntu虚拟机内安装一些工具(之后也会使用到)与读卡器驱动
1 | $ sudo apt-get install build-essential git cmake g++ |
安装完毕之后,使用 sudo pcsc_scan
命令,如果出现了 Japanese Chijou Digital B-CAS Card (pay TV)
类似的字样,那么B-CAS卡的安装和驱动就顺利完成了
笔者在这里碰到过两个问题,一个是B-CAS插反了,没读到芯片(汗),另一个是B-CAS卡无效问题。
B-CAS卡如果无效的话,是会顺利出线上述字样的,但是之后无法正常使用录制电视,可以将B-CAS插上电视看一下是否有错误提示。
另外如果使用的不是NEC读头的读卡器,可能会没法扫描出或者没法启动pcscd(参考的原文章作者碰到了这个问题),读者可以自行搜索相关方法或参考下方参考文章链接。
由于日本地上波加密后进行广播,直接录制的话也没法播放和保存。因此我们需要在接收信号的同时使用B-CAS卡进行解码并无视加密。实现这个的是一个叫libarib25的库。
这个库需要编译。
1 | $ wget https://github.com/stz2012/libarib25/archive/master.zip |
完成安装
我们需要安装recdvb这个录像指令,之后的录像管理都会调用这个指令来进行。
源代码是公开的但是没有放在github上,需要编译安装。
1 | $ wget http://www13.plala.or.jp/sat/recdvb/recdvb-1.3.2.tgz |
完成安装。
安装之后就可以使用这个指令直接录制电视节目了。
比如
1 | $ recdvb --b25 --strip <channel> <seconds> test.m2ts |
channel根据地区,放送电波塔不同,数字不同,可以在这里进行确认。
另外,可以使用
1 | $ recdvb --b25 --strip --http <port> |
指令,在本地起一个服务器推送流,
使用VLC或者IINA可以打开
1 | http://[IPアドレス]:8080/[channel number] |
channel number就是上边那个数字。
但,在这之前,
需要在Ubuntu虚拟机的/etc/hosts
中设定连接者的ip域名(为了保证安全),
我的话并没有在外网访问Tuner Server的想法,并不需要这样的设定,因此修改源代码重新编译安装。
按下 Ctrl+C
关闭推送流服务器。
Mirakurun是一个Node.js编写的系统,具有同时多频道录像,多天线管理,优先度处理功能。
以及提供了各种API,以方便对应各种客户端的请求,在外网无法直接访问服务器也可以管理预约录制节目等。
安装Mirakurun可以参照
https://github.com/Chinachu/Mirakurun/blob/master/doc/Platforms.md
以下内容方便参照部分搬运
请参照 https://github.com/nodesource/distributions/blob/master/README.md#debinstall
1 | sudo npm install pm2 -g |
1 | sudo npm install mirakurun -g --unsafe-perm --production |
主要是对Tuner进行配置,
1 | mirakurun config tuners |
这里卡了很久,一直没法成功录制,但最终注释掉了一些奇怪的配置就搞定了
1 | - name: PX-S1UD-1 |
1 | mirakurun restart |
重启mirakurun之后查看 pm2 log,如果没有错误正常开始Recording,表示搭建成功。
频道的话对Tuner设置成功之后会自己更新频道并更新节目列表,因此无需其他操作,一个天线的情况下耐心等待5分钟到10分钟左右即可。
到这里为止,我们所有服务端的设置基本就完成了,Mirakurun本身已经提供了API,可以通过API进行调用获得节目信息或者录制,也提供了Http流推送,来方便其他客户端进行录制。
API使用等可以参阅
我们需要一个可视化客户端来帮助我们管理预约,对Mirakurun进行下达命令。
于是我们需要安装Chinachu。
由于这里开始,我们可以在Docker中也能完成这样的任务,搭建过程就省略,取而代之大家可以到
查看DockerFile,或者参照DockerFile自行编写自己需要的脚本来进行搭建Chinachu。
如果读者按照我的镜像进行搭建,需要注意如下(自己编写Docker脚本时也需注意一些Docker问题)
时区问题
/etc/localtime:/etc/localtime:ro
Chinachu 的预约/设置数据
日志问题
1 | #!/bin/bash |
不要忘记挂载录像目录
不要忘记暴露端口
Chinachu的官方配置文档在这里
https://github.com/Chinachu/Chinachu/wiki/Gamma-Configuration
基本没有什么太多需要注意的,将预设内容拷贝一份挂载进Docker就可以。
需要注意vaapi相关内容,下述。
之后就启动Docker容器吧,启动脚本就请各位自行挂载并启动了
也可以使用docker-compose来启动,docker-compose up
输入 NAS 地址和端口号后进入Chinachu界面并能看到节目表基本就算成功了。
录制后是m2ts的TS文件,我们可以利用 NAS 闲暇 CPU (x86架构的 nas 基本都具有硬件加速)将 TS 文件转换成 mp4,缩小文件体积保存等。
需要注意的是,如果我们需要使用vaapi(Intel CPU的硬件加速解码),那么我们在启动Docker时需要使用root权限,否则无法访问 /dev/dri/renderD128
硬件。
但是录制后的文件的所有者就会变成root,其他应用程序读取或修改的时候会有一些问题,因此我推荐在录制后,转码后,可以自己编写脚本来重新设置权限。
1 | $ chown <uid>:<gid> </path/to/file> |
ffmpeg的相关参数我在这里贴出自己的进行共享,你当然也可以参照官方文档进行调整。
1 | $ ffmpeg \ |
注:这里的环境PATH比较微妙,请一定使用绝对路径。
我写了一个 shell 脚本,将脚本命名成你喜欢的名称,假设 afterRecord
,不要忘记赋予执行权限,在 config.json
中修改
1 | "recordedCommand": "./userScripts/afterRecord", |
你可以根据自己需求修改转码设置,或者添加LINE通知等功能,打造属于自己的录像服务器。
直接把 WebGUI 暴露在公网上还是很危险的,我们给界面添加一个密码输入,保证录像服务器只能自己用。
由于我用了 docker-compose ,可以很方便的添加 nginx 并设置反代
1 | $ sudo htpasswd -c /path/to/.htpasswd <username> |
在服务器上直接生成的可以跳过
1 | ...... |
1 | $ docker-compose restart |
刷新界面,此时应该被要求输入密码
通过自己的脚本来创建的文件群晖是无法增加索引的,以至于在DLNA广播中无法显示我们转码或者录制的文件
假设我们的录像文件直接存储在/path/to/record/folder
下面,我们可以编写脚本
1 |
|
其中第三行 cd
不可漏去,否则群晖不会在此文件夹中执行 find
。
保存脚本,假设 reindexTVRecorded
,在 控制面板 - 任务计划 - 新增 - 计划任务 - 用户脚本
,输入计划,输入任务运行脚本保存即可
Caption2Ass.exe
等windows程序-filter_complex channelsplit
或者-dual_mono_mode main
对以上问题如果有办法解决的读者请联系我 m__m
在手中有NAS的情况下1w不到搭建一个这样的录像服务器还是性价比很高的,之后就可以随时随地观看一些并不那么需要大屏幕观看的内容。
文章中还是充满了自己自身的需求,另外文章编写的时候已经间隔搭建完差不多有一个月左右的时间,有些细节可能没有办法很到位描写清楚,如果你有什么问题,可以在评论区留言。
]]>Raspberry Pi 3+Chinachuで地デジ録画サーバー構築
Linuxの自宅サーバをテレビ化して家中どこでもテレビが見れる環境を作ろう(2)
通过Nginx反向代理配置Basic Authentication实现kibana的访问安全
2017/01/30 時点での録画サーバ構築手順
NASを持ってる方多いと思いますし、NASは24時間起動してるので、新しいデバイス買わなく節電できて録画サービスを任せろう。
記事書く時点だけの有効性を保証します、エンドユーザー、コンピュータ初心者向けではない。
以下の手順は全て自己責任で、何かしらの問題が発生しても自力で対処できる方のみ実行してください。
テレビ番組のコピー、配信は違法となる場合があります。使用についても十分注意して下さい。
この記事を参考にしたことにより生じたあらゆる損害について、著者は一切の責任を負いません。
大体こういう感じでやっていきたいと思います。
VMにアンテナのドライバをインストールします
1 | $ wget http://plex-net.co.jp/plex/px-s1ud/PX-S1UD_driver_Ver.1.0.1.zip |
完了。
アンテナドライバ最低3.15のLinux カーネル必要なので、Synology NASのLinuxカーネルは3.10なのでVMを立って使います。
もし今後 NAS のカーネルが3.15以上になったら、次回 https://github.com/Chinachu/docker-mirakurun-chinachu の Docker イメージを使ってみたいと思います。
カードリーダーソフトとビルドツールのパッケージをインストールします。
1 | $ sudo apt-get install build-essential git cmake g++ |
完了後、sudo pcsc_scan
を実行して、Japanese Chijou Digital B-CAS Card (pay TV)
みたいものでたら完成です。
しかし、私はここ2つ問題遭った、
1つ目は入れ間違えたww、
2つ目はB-CASカード無効問題、B-CASカードを最初にテレビに入れて見てみたら多分分かると思います。
型番も問題になるかもしれない、参考した記事の作家さんは遭ったのでそちらの記事をお越しいただければと思います。
日本の地デジ放送は暗号化された状態で配信されているため、そのまま受信して保存すると再生や複製の際に問題が起こる。そこで、B-CASカードの情報を使って受信と同時に復号するのが望ましい。これを実現するライブラリがlibarib25だ。
コンパイル必要です
1 | $ wget https://github.com/stz2012/libarib25/archive/master.zip |
インストール完了です。
録画ソフトはこれを使って録画しますので、recdvbをインストールします。
ソースコードあるんけど、Githubに載っていない。
1 | $ wget http://www13.plala.or.jp/sat/recdvb/recdvb-1.3.2.tgz |
インストール完了。
この時点で、コマンドでの録画が可能になった。例えば、
1 | $ recdvb --b25 --strip <channel> <seconds> test.m2ts |
チャンネルは受信タワーによる違いますので、こちらから確認できます。
また、
1 | $ recdvb --b25 --strip --http <port> |
を使ったらリアルタイムストリーミングを配信します。
Windows / MacのVLCかMacのIINAからURLを開いたら直接見れます。
1 | http://[IPアドレス]:8080/[channel number] |
チャンネルは上と同じです。
だが、その前に、
VMの/etc/hosts
を設定しなければいけない(安全保障かな)、
でも私のチューナーサーバーはWANに公開するつもりはないので下のリンクを参考して解除しました。
Ctrl+C
を押して終了させます。
チューナーサーバーMirakurunではWeb APIを提供して、録画コマンドの並列処理や、複数チューナーの管理、優先度処理など様々な機能が利用できます。
Mirakurunのクライエントを通じて外でも番組を予約もできる。
Mirakurunのインストールはこちらへ参考していただければと思います。
https://github.com/Chinachu/Mirakurun/blob/master/doc/Platforms.md
ざっくりここで書きます
请参照 https://github.com/nodesource/distributions/blob/master/README.md#debinstall
1 | sudo npm install pm2 -g |
1 | sudo npm install mirakurun -g --unsafe-perm --production |
Tuner設定
1 | mirakurun config tuners |
ここで半日間かかった!わけわからんパラメーターを抜いたら使えました!
1 | - name: PX-S1UD-1 |
Mirakurun再起動します。
1 | mirakurun restart |
pm2 log
で状況を見てみましょう、特になんのエラーが出てなく、Recording
が出たら多分大丈夫です。
チャンネルの設定は Mirakurun は自分が取得しますので、5-10分ぐらい待てばいい。
ここまでチューナーサーバーの設定は完了しました。
MirakurunはAPIとHttp Streamingも提供してるので、
APIの使用はここへ
でもGUIクライエントがないとめんどくさい、Chinachuをインストールします。
Dockerのイメージを作りましたので、DockerFile参照して使うか、自分がカストマイズするもよい。
もし私のDockerFileを参照して立ているなら、下記を注意してください。
(Dockerを利用する方も見るといい)
タイムゾーン問題
/etc/localtime:/etc/localtime:ro
をマウントChinachu の予約、設定データ
./chinachu/data:/chinachu/data
./chinachu/rules.json:/chinachu/rules.json
./chinachu/config.json:/chinachu/config.json
膨大ログ問題
1 | #!/bin/bash |
録画ファルダのマウントをお忘れなく
/volume2/TVRecorded:/chinachu/recorded
ポートの公開
公式ドキュメント
https://github.com/Chinachu/Chinachu/wiki/Gamma-Configuration
基本、コピーしてちょっとカストマイズすれば大丈夫。
VAAPIについてはあとトランスコードの部分で説明します。
それで、Dockerを起動して、docker-compose
も利用可能ですので、自分のニーズをあわせてChinachuを起動します。
NASのURLとポート番号をブラウザに入力して下の画面見れると成功です。
録画したファイルは大きな生TS、 大体 x86 アーキテクチャの NAS はハードウェアアクセラレーションついてるので、速いスピードでmp4にトランスコードして、どこでも見れるコーデックにしながら、ファイルサイズも小さくさせる。
注意するべきのはDockerにvaapi(Intel CPUのハードウェアアクセラレーション)を使うと、rootの権限でアプリを走らないと行けない(/dev/dri/renderD128
をアクセスために)
だがこうすると、録画したファイルはrootが所有者になって、他のアプリの編集は出来ないので、録画後、トランスコードした後、chownを走らせましょう。
1 | $ chown <uid>:<gid> </path/to/file> |
ffmpegのパラメーターも共有しますが、自分のニーズをあわせて公式ドキュメントを参照して調整できます。
1 | $ ffmpeg \ |
注意:ここのPATHは絶対にフルパスを指定してください、そうじゃないと妙なところに行っちゃいますよ。
名前をつけて、afterRecord
とし、 config.json
に
1 | { |
を編集して。
自分のニーズ合わせてスクリプトをカストマイズして自分唯一無二のサーバーを作りましょう!
僕はLINE通知を入ってて録画したら通知がLINEに来ますね。
WebGUIそのままWANに公開するとちょっと危ない、入るときパスワード機能を入れましょう、自分だけ入ることを確保しましょう。
僕docker-compose を使ったから、すぐ nginx を追加できます。
1 | $ sudo htpasswd -c /path/to/.htpasswd <username> |
サーバーで生成する方はスキップー
1 | ... |
1 | $ docker-compose restart |
ブラウザをリフレッシュして、ここでパスワードが求められてるはずです。
自分のスクリプトで作ったファイルは NAS は知らないので、DLNAとかで出てこない。
そこで再インデックスする必要があります。
仮にすべて録画したファイルは/path/to/record/folder
の第一層でいる、このようなスクリプトを書いて
1 |
|
reindexTVRecorded
を名前を付けて、 Control Panel - Task - New - Scheduled - User Script
、時間とか選択して、スクリプトのパス入れて「はい」を押したら完了。
Caption2Ass.exe
などwindowsプログラムは使ってない-filter_complex channelsplit
か-dual_mono_mode main
心当たりがある方教えていただければ幸いです! m__m
NASがある場合は5000ぐらいで立てるのはいいと思います、今後どこでもテレビを見れると嬉しい。
記事の中は自分自身の特集のニーズいっぱい詰まってるし、記事を書くときも立てたから一ヶ月ぐらいがあって、抜けている箇所があるかもしれないし、変な日本語もあるかも、もし何が不明点があればコメントで書いてくださいー
Raspberry Pi 3+Chinachuで地デジ録画サーバー構築
Linuxの自宅サーバをテレビ化して家中どこでもテレビが見れる環境を作ろう(2)
通过Nginx反向代理配置Basic Authentication实现kibana的访问安全
2017/01/30 時点での録画サーバ構築手順
最後まで読んでいただきありがとうございました!
]]>这个动画也只有第一集是现实中出现的场景,后边都是未来在天上在船上并没有日本的景色。
非常遗憾自行车店好像在翻新,去年在Google Map上貌似还有的样子
小高商店 2013 年的时候好像因为车站周围改造所以关店了,好遗憾
非常遗憾的是,没有07:12往三鷹的电车与7:15的中野非始发电车,样式也并不是动画的样子。
刚才还在5番線的但事实上这里的镜头确实是4番線向5番線方向的景色,但是左边的广告牌却是5番線的广告牌
接下来就是男主被追的场景,这里大多都一模一样。
だるま 2013 年关店的,不过其他的地方都能对上
从这里开始难度就变得好高,大家凑合看吧
高架电车没有地方能拍,就跑的稍微远了一点,不过还是没能拍好
正在制作 valiancer 的中◯屋工厂
大山交差点这里并没有完全按照现实世界的布景画
到这里就全部结束啦,顺带一提主人公的家是真实存在的,不过因为私人房屋的原因不会上传到SNS等地方,如果有兴趣的访问的话也请一定不要给对方带来困扰。
Google Maps:https://drive.google.com/open?id=1fTiF9I8exv6jFB-86H49elu6EntfaA1q&usp=sharing
]]>1話ラストで未来へ行ってしまって以来、完結編の最後に至っても2014年の東京、千葉の景色が再度登場することはありませんでした
なお本作品の舞台には高校や閑静な住宅街を含みます。もし訪問される際は現地の方へ最大限配慮して行動されるようお願いしたく思います。
津田沼サイクルなくなった、リニューアル中みたいです、グーグルマップによる去年まだあるらしい、残念
小高商店もなくなった、調べたら2013年の時駅周辺改造のため、本当残念
07:12の三鷹行き電車と07:15の中野行き非津田沼駅始発電車はない、仕様もアニメのものではない。
作中では5番線になっているが実際描かれていたのは4番線からの景色。でも左端に写っているユザワヤの広告は5番線の広告。
これからは主人公追われた景色。大体一緒です。
だるま 2013 年閉店ですが、他の施設ちゃんと合った。
難易度高くなった
高架の電車はどこでも取れないから、ちょっと遠いから取ったけど、良くないね
ヴァリアンサーを生産している中◯屋工場です
大山交差点周りは今までと違ってあまり実際の景色に忠実ではない様子。看板や窓の形など、細かいパーツが一致する程度でしかありませんでした。
ここまで全部終わりました、ちなみに主人公の家は本当に存在している、個人宅なので掲載はしません、興味があれば訪れる時絶対迷惑かけないように
最後までご閲覧いただきありがとうございました。
Google Maps:https://drive.google.com/open?id=1fTiF9I8exv6jFB-86H49elu6EntfaA1q&usp=sharing
]]>包括以下内容:
在试用的过程中,碰到了一些问题,做一个整理。
首先需要到 https://apps.twitter.com/ 在这里按提示创建应用,获得应用的 key 与 Secret。
https://developer.twitter.com/en/apply
到这里按照提示申请API权限,并附上 app ID(app ID相关解释:https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/overview )
申请完成后会收到邮件
webhook 的地址要求通过 CRC 测试,详细要求可以查看
https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/guides/securing-webhooks
写了一个自己的demo,关于CRC测试的代码:
https://github.com/xingoxu/twitter-like-downloader/blob/master/routes/twitter.js#L13-L23
1 | POST: |
Bearer TOKEN
可以通过https://api.twitter.com/oauth2/token
接口获得
注意
1 | GET: |
获取到刚才的 webhook id
之后
1 | POST: |
注意这里需要用OAuth 1.0(用于识别注册的user id)
注册完成后不会有任何返回,HTTP Code: 204 No Conent
注册完成后可以通过
1 | GET:https://api.twitter.com/1.1/account_activity/all/env-beta/subscriptions/list.json |
可以收到
1 | { |
随便对一条推特点赞
可以收到推特来的 webhook object。
自己用这个写了一个推特的bot,可以作为参考。
https://github.com/xingoxu/twitter-like-downloader
以下のものが含まれます:
使う時実際起こった問題を書きました。
まずここで https://apps.twitter.com/ チュートリアルに従ってアプリを作って、アプリの key と secret を取得します。
https://developer.twitter.com/en/apply
ここで権限を申請します,app ID の添付を忘れずに(app ID について:https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/overview )
申請成功したらメールが来ます
webhook は CRC テストを合格しなければ登録できない、具体的な要望はここに書いている ->
https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/guides/securing-webhooks
自分もNode.jsのdemoを書きました、一応参考になれば:
https://github.com/xingoxu/twitter-like-downloader/blob/master/routes/twitter.js#L13-L23
1 | POST: |
Bearer TOKEN
はhttps://api.twitter.com/oauth2/token
で取得できます。
注意
1 | GET: |
さっきの webhook の id を取って
1 | POST: |
注意すべきところ:ここAuthorization は OAuth 1.0(user id 認識ため)
リスポンス内容はない、HTTP Code: 204 No Conent
登録したらここに見えます
1 | GET:https://api.twitter.com/1.1/account_activity/all/env-beta/subscriptions/list.json |
これを受けれます
1 | { |
好きなツイートをいいねすると
ツイッターサーバーから webhook object 受けれます。
最後、Account Activity API使ってる自家用ツイッターBotです、参考になればぜひ
https://github.com/xingoxu/twitter-like-downloader
最後まで閲覧いただきありがとうございました。
]]>仔细想想还真的是2017年经历了太多太多事情,很多事情甚至自己都没有想到,感觉自己非常幸运,总的来说是一个很开心的一年。
按时间顺序
怎么说,年前就有想跳槽的想法,其实在萌购干着也挺好的,老板也承诺说毕业之后的工资多少多少,价格嘛也不低(跟饿了妈差不多),但始终是有那么点没有安全感,终于逮到个机会去了饿了妈面试,虽然自己是个菜鸡,不过面试的问题还算是都自我感觉挺好的答了下来,于是就很顺利的跳槽到了饿了妈。
也算走到了算是一个不太容易倒闭的公司,体验了各种大公司的流程,效率也挺高的,时间嘛也还行自己手脚比较快所以基本会有一定的空闲时间,不算很多,但可以。
刚进饿了妈不久,就要收拾东西准备攻略自己一个人出去玩啦。半年前的既定安排跟跳槽也无关,不过当时想着4月底5月初的时间段怎么说也得三方啊毕业的准备都差不多了吧,那又是谁知道这个点了我自己居然还会跳槽,真是。。。
嘛操着自己零零碎碎平假名和片假名,也没跟太多人说话,现在想起来我当时到底是怎么旅游的都完全不怎么会说日语,顺顺利利的玩了10天,肥肠快乐,嘛钱也用了不少,差不多一共两万左右吧?
一霎眼毕业了,当时好像没有什么感觉,取了毕业证书,学位证书,回家就往公司的系统上传表示7.1日起就可以拿正式工资了,只有这点才让我感觉到了毕业。不过现在想想,我居然已经是个社会人了,而且已经实习+上班上了一年了,时间的力量还真是强大,把自己给塑造成了什么样只有回头看的时候才能知道。
我对学校没什么好感,对周围同学也没什么太多好感,4年自己也不知道自己干了什么,只是埋头学了很多东西,所以这4年,嘛也就这样。
旅游回来之后发现自己只有一个月时间就要考N2于是工作之余还不停的去做之前买来没做的练习再去查字典,最后考前一星期还买了一本书再做练习,直接就上了考场。考完回来感觉应该能过吧,虽然有一半的语法题我是瞎蒙的,有一篇阅读没有时间看。这种没有范围的考试真的非常吓人,又或者说因为是第一次正正经经考一个完全自学的语言所以会如此害怕。
复习非常累,考试也很累,幸好最后顺利通过,还是很开心的(分数不高啦)
这算是下半年一直在做的一件事情吧,从9月初开始试试的心态投了一封简历,结果到最后面试走完被发了offer真的非常非常开心又意外,一个是LINE是日本的企业之中应该是我心中最想去的一个企业,Google也好Twitter也好也很想去,但那些真的水平太高,自己99%是不太可能的,不过LINE的话最初我觉得自己可能70%不太可能,不过最后居然能进是非常意外的,另一个意外就是自己其实日语也就是三脚猫水准,也不要说三脚猫了,一脚猫吧,顶多也就看看小学生向的普通动画,在这之前都没跟日本人说过话,推特也只是在去日本玩送东西给太太的时候结下的太太聊天,聊的也不多还不需要太注重细节,就这么烂的水平,居然最后被采用了。
然后就是递签证,返签证,去日本找地方睡觉,上班这样的过程,签证只花了一周不过递签证跟返签证还真是艰辛前前后后块花了一个半月,嘛只能算是好事多磨。期间当然是在饿了妈当没事人一样刷KPI,我觉得如果我不走的话我KPI至少有B吧,A能不能有就不太清楚了。
第一次离开自己家自己一个人住,唔太幸福了,小黄本放题啊~~
要说原因的话,也不太那么好明着说吧,嘛自己来日本的时候的确也是觉得哇这里真好真舒服,想来这里上班呢,另一个是2017下半年也的确发生了很多事,让自己对周围的环境有了一些看法吧。
天呐看看去年的计划,什么rxJs,什么后端,什么可视化前端,什么游戏开发,完全没有学嘛。
2018年的话,先把欠账还清吧,下的动画啥的赶紧看完,不过游戏啥的基本都完成了还算是,摸鱼上手(笑)
适用 Vue.version < 2.5 && Vue.version >= 2.2
其实我个人一开始很讨厌 TypeScript 这个东西,就是因为讨厌 Java 的啰里巴嗦,突然在我眼前出现了 Javascript,便爱上了这门语言。
但现在的我稍稍又觉得这样的东西其实还行,只使用类型系统也并没有完全限制 Javascript 本身的灵活性,并且他帮助我不会犯一些低级错误,而且还能配合 Visual Studio Code 的提示,我觉得这个还是很不错的,最近忙起来的时候,甚至经常把两个输入框的 value 直接进行比较了,于是就想尝试一下 TypeScript。
Vue 2.2 以上之后,官方给 Vue已经添加了很多类型声明,那么我们就来实践一下在单文件 Vue 中使用 TypeScript。
1 | { |
表示对 .ts 文件编译时使用 ts-loader 进行读取,appendTsSuffixTo 是为了让 tsc 对 vue 文件能够当成一个 module 进行处理,以解决 moudle not found 的问题(tsc 本身不认识 vue 结尾的文件)
1 | declare module "*.vue" { |
也是为了让 vscode 在 ts 文件中识别 vue 结尾文件
1 | { |
allowSyntheticDefaultImports
是为了能够用 es6 形式的 import,其他就参照 Vue 和官网的弄了个最小化的 json。
npm run dev
跑起来!在这里,我们假设使用 Vue 官方的 webpack boilerplate,对 Hello.vue 进行一下改造。
在模板的 msg 下新增一行
1 | <h2>Say Hello Times: {{ count }}</h2> |
并将 script 部分修改成
1 | <script lang="ts"> |
这段代码没有什么太大的问题
接着我们改造一下 App.vue
1 | <img src="./assets/logo.png" @click="sayHello"> |
1 | <script lang="ts"> |
也就是说,像 refs 这种动态的在运行时才能确定的东西,如果需要在 coding 过程中静态化,则需要在 interface 中对其进行声明,写的 code 稍微有点多,不过可以接受。
注: App.vue 修改成
lang=ts
后,顶层的 main.js 需要换成 main.ts 并修改 webpack 入口点,否则发生 file not found 错误
官方的另一种推荐做法是 vue-class-component
,不过 demo 和 readme 有点小问题,可把我这个 TypeScript 新手给难到啦,提了 pr 希望快快通过。
让我们看看使用 vue-class-component
之后的 Hello.vue
1 | <script lang="ts"> |
再让我们看看 App.vue
1 | <script lang="ts"> |
非常 Cool,非常精炼,暂时没有想到可能会发生的没法解决的因为 vue 或者 vue 组件 和 TypeScript 水土不服的编译错误,而且都有了类型和提示。
尤大佬说在接下来的 Vue 2.5 还会加强一系列的 TypeScript 支持(链接),不知道是怎样的支持呢。
另外,欢迎大家在评论区发表 Vue + TypeScript 的使用场景以及你遇到的错误。
Vue.version < 2.5 && Vue.version >= 2.2 適用される
Vue 2.2 から、Vue にいろんな公式型宣言を提供しており、さっそく、単一ファイルコンポーネントに TypeScript を試してみましょう。
こっちは webpack2
1 | module: { |
.ts のファイルを ts-loader で読み込むappendTsSuffixTo
は vue を module として tsc でプロセスして、module not found の問題を解決する(tsc は .vue ファイルが知らない)
どんな名前もいい、どこでもいい、tsconfig.json の include PATH にいればいい、必ず .d.ts を名前の終わりします。
1 | declare module "*.vue" { |
vscode の .ts ファイルに .vueファイルも知らせます。
1 | { |
allowSyntheticDefaultImports
は es6 の import を直接使えるの option
npm run dev
いきましょう!こっちは vue-cli の webpack boilerplate を例として、Hello.vue を改造しましょう。
html template の msg の下に
1 | <h1>{{ msg }}</h1> |
script の部分を
1 | <script lang="ts"> |
こうして改造します
親としての App.vue を改造してみて
1 | <div id="app"> |
1 | <script lang="ts"> |
refsといった動的なもの、interface に宣言して、typescript にオートコンプリートを使えます。
App.vue の
script
をlang=ts
変更すると、main.js を main.ts に変更する必要があります、webpack の entry も忘れないでください,そうしないと file not found のエラーが発生する可能性がある。
コードはちょっと多いね、公式サイトによるの vue-class-component
を使ってみますか?
vue-class-component
の demo と readme はちょっと問題がある、TypeScript の新入りの私が困った、pr を提出した、速くマージされて欲しい。
vue-class-component
を使っている Hello.vue の script 部分
1 | import Vue from 'vue'; |
で、App.vue
1 | import Vue from 'vue'; |
随分清潔になりました、オートコンプリートもバッチリ!他の vue コンポーネントと TypeScript の不具合は一時的に考え出来ません。
Vue 2.5から TypeScript のサポートはどんどん増えますと言います、どんなサポートですね〜
日本語まだ下手ですから、変なところいっぱいと思います、コメントエリアに指摘すれば幸いです。
最後まで閲覧いただきありがとうございました。
]]>昔のやり方は、Cookie に直接保存する。サーバーストレージはまだそんな安いの状況下で、たくさんのウェブサイトはユーザーの登録そういうインフォメーションを変化してサインして Cookie に保存する。
変化やサインは、md5+salt、または secret を使って双方向の暗号化するとかの方法。
ウェブサイトに二回アクセスとしたら、Cookieに指定のkeyのvalueを検証する、それはただしかどうか。
こうやっていいところは:
サーバーストレージ占有なし、Cookie はユーザーの情報です
こうやって悪いところは:
ユーザー情報盗むはやすい、特にhttpsなし、中間者攻撃されたら、悪い人にログインされたことはできる。
また、別々に保存するのデータを改ざんされるはやすい。
計算力とストレージの速い発展、問題は次々に現れた。保存希望のユーザー情報はますます多くなる、Cookie のサイズ制限は少ない。
原理的には、Session は Cookie です。
サイトにアクセスとき、サーバーから唯一の Session ID を配ってCookie に保存する。ログインのとき、この Session ID による、サーバーに Session Object を作る、このオブジェクトにuser idとか、状態というユーザーの情報を保存している。
Session ID は Session Object を作るのときに配れも可能です、Session IDの作る方法は時間によるに限らない、sidの唯一を保証すればいい。
Session Object のストレージ場所も選べる。Sessionはとても大事ですと思われなら、mysql に保存するは可能です、そうではない場合は、redis に、メモリにも可能です。
だから、Sessionはとてもフレキシブル。
Session は過去の技術ではない、今はたくさんのウェブサイトに使われている。その原因は、httpしか問題いません。Internet Explorer >= 10 の場合も CORS に Cookie の伝送が可能ですから、問題ない。
いいところ:
クライエントサイド sid しか見えない
悪いところ:
情報を取得する、一つ query 必要です。
盗むも可能ですが、Session / Cookie の問題ではない、http の問題です、httpで何も見える。
いいと悪いは時代に応じるです、Cookie に保存するときは、サーバーの計算力は低い、memcacheやredisもない、Sessionの時間はかかる、今はこれは決して悪いところじゃない。
Session と Cookie はフロントエンドにとって何をする必要はない、サーバーは Set-Cookie の http header で sid と Cookie の更新を完成することはできる。
上記2つの方法は、2つの異なるアイデアを表しています。一つは情報をクライエントサイドに保存する、一つはサーバーにする。
フロントエンドとバックエンドを分けるときは、上記の2つアイデアも Cookie なしに進化する。
一つは
Session Token を取って、JSON、または 他のhttp header に伝送する
一つは
JWT(JSON Web Token) 情報をクライエントサイドに保存するというアイデアを表す。Cookie とちょっと似ているけど,情報を base64 に変化して、secretでサインして、一緒に token になる。
クライエントサイドに保存するのいいところは:
情報はクライエントに保存しているから、コードに直接処理はできる、ロードバランスとかの心配いらない。
また、Session の期限切れば、データベースに delete の必要がある。
悪いところは:
情報多くなるとき、Token は長くなる、http request は大きいになる、伝送の時間がかかる。
JWT の payload は base64 コーディングする、誰か標準に通じれば、内容を見られます。
Token Based 認証はフロントエンドに保存して、コーディングは必要です、一般はlocalStorageで。
だから、Token Based 認証は XSS に攻撃される可能性はある、Cookie Based 認証は CSRF に攻撃される可能性はある。
いくつかの単語をすべての場合に要約することはできません、Token と Cookie また 情報をクライエントサイドに保存するとサーバーにするの場合を想像する、どんな方法を採用しようか、現業務を基にして、ちょっと長いのビジョンで選択を考える。
]]>直接在Cookie中存信息可谓是上古时代的操作了,在服务器还没有那么便宜的情况下,好多网站选择将用户的登录信息存在cookie中,他们把用户名或者用户id转换并签名之后,直接存入Cookie,如果有其他需要的信息,也是如此操作
转换或签名可以是加盐md5,也可以是使用secret的双向加密
用户第二次访问网站的时候,代码中对这段信息进行验证,看看是否是正确的签名的
这样做的好处是:
不会再占用服务器资源,直接就在cookie中读取数据,获得结果
坏处是:
登录凭据容易被窃取,尤其是那个年代还没有流行https,如果被中间人了,或者以另一种方式拿到了cookie,那就会被窃取登录,另外,每个数据还可能是分开存储的,因此容易被篡改
当然那时的互联网也并没有那么发达,cookie也就存存用户名什么的用于显示
后来网速变快了,web 应用高速发展,大家意识到了很多问题,cookie 大小不够啊,cookie 每个 key 都这么搞一下暴露太多了等等
从原理上来说,Session 就是 Cookie
客户端进入网站后,服务器分配一个 Session ID 给客户端种入 Cookie,用户登录时,在服务器查询 Session ID,在服务器写入 Session Object,这个对象里存了用户的登录数据,比如 id 啦,用户名啦,登录状态 / 角色等等
另外分配 Session ID 也可以是懒分配,也就是等到在服务器存 Session Object 的时候再分配也没有关系,Session ID 的分配可以是用 UserID 来进行加密分配,也可以用毫不相关的时间等信息进行加密分配,只需要保证这个 sid 唯一,不容易被伪造即可
Session 的存放也是可重可轻,如果觉得 Session 很重要,那么可以放入 mysql,如果觉得 Session 不怎么重要,甚至可以放入内存,重启丢失
Session 到至今还是非常非常多的网站在用,原因就是在于其实除了 https 以外的问题,并没有什么问题,IE >= 10 之后,Cookie 也可以跨域,那么 Session 就没有什么问题
好处是:
在客户端除了 sid 以外,看不到任何信息,当然不太容易篡改
坏处是:
取 Session 的时候,是会需要再 query 一次的
也容易被窃取,当然这并不是 Session / Cookie 的锅,http 下,啥都是一清二楚的
另外,优缺点都是相对于时代来说的,存 Cookie 的时代服务器的性能不高,也没有 memcache 或者 redis 这种东西,存入 mysql 就需要再 query 一次,负载均衡当然不能同步 内存中的 Session,Cookie 成为了首选,那么现在呢,这点算力恐怕算不了什么,那么 Session 的那个坏处,就应该被划掉,Session 理所当然成为了流行的会话管理方式
Session 和 Cookie 都不需要前端介入,服务端通过 Set-Cookie http 头就可以完成 sid 和 Cookie 的更新
上边两种方法代表了两种存登录凭据的思想,一种是把凭据存客户端,一种是把凭据存服务端
那么随着前后端分离的运动,上边两种的登录凭据的思想也发展出了两种不使用 Cookie 的方法
把凭据存服务端的 Session,把他的Token,单拿出来,在JSON中传递,或者在 http 头里传递或者其他方式传递
JWT(JSON Web Token) 代表了把凭据存客户端的思想,和当时的 Cookie 有点像,登录的时候把那些需要的信息 base64 编码作为一段,然后再对这些字段用 secret 进行签名,连起来这么一段 Token 去发给客户端作为凭据
凭据存在客户端的好处是:
因为登录状态都是跟着客户端跑的,时效信息都存在客户端,Session 如果过期了,要对 Session 数据库进行垃圾清理,那么凭据存在客户端就不需要,而且因为都是跟着客户端跑的,在服务器扩大搞集群,搞异地多活,就不需要考虑读数据库这种事情,因为都是客户端请求为 based ,随便哪个服务器来 handle 请求都没有问题
凭据存客户端坏处是:
当凭据内容越来越多,Token 也会越来越长,每一次请求都会携带这么大这么长的内容,显然不是非常合适
JWT 还有个问题就是中间那部分是 base64 编码的,如果熟悉标准的话,等于就是明文存储凭据了,虽然不能改,当然还是能看到
Token 类的鉴权需要前端参与并存储,存储一般会放在 localStorage等地方,因此其实是比较容易受到 XSS 的影响
Cookie 类的鉴权容易受到 CSRF 的影响
其实只言片语还是没法概括到所有的情况,只能大体的对Token 或者 Cookie 以及 凭据存服务端或者客户端的优缺点进行想象,究竟去使用哪一种鉴权方式,还是应该基于业务,对业务有非常深入的理解,以及稍带一些长远的思考
]]>