duangsuse::Echo
716 subscribers
4.25K photos
130 videos
583 files
6.47K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
duangsuse::Echo
Photo
duangsuse 是这么分的:

== 对象状态:

+ 无论什么 vertx 应用,都会用到 Logger,使用 LoggerFactory.getLogger(this.javaClass.name) 拿到一个 Logger
+ 服务程序需要实例化一个 HttpServer!,但不能直接在 <init> 方法里实例化,保存下来作为 lateinit var

+ 服务程序需要保存一个状态:待随机选择的图片文件列表,因为开始时可以不扫描文件,作为 MutableList<Path> 保存

== HTTP 服务器部分:

+ 基于 async chain 的 vertx 应用(AbstractVerticle)都有一个基于 Promise (Future) 的 "main(String... args)" 方法,覆盖它以添加启动逻辑
override fun start(init: Future<Void>)

+ start 里要先完成 indexImanges,再去 startServer,全都是异步进行的,用 Promise 表示它
Promise.all(indexImages, startServer)

但是 startServer 包含整个应用程序真的『业务』代码路径,如果它失败应用程序也该失败才对,可以手动 setHandler,但是应该抽提出来,ES6 里也有这个方法:
fun <A, B> Future<A>.catching(chain: Future<B>): Future<A> = this.setHandler { if (this.succeeded()) chain.complete() else chain.fail(this.cause()) }


+ 需要一个 server,而且这个 server 应该设置一个 requestHandler 才能用,那就抽象成
private fun createHttpServer(router: Router): HttpServer

+ 需要一个 router,这个是应用程序自己设置的,那就抽象成 drawRoutes
private fun drawRoutes(): Router

+ 唯一的业务代码就是随机选择图片发送,发送文件的操作封装在 httpServer 里了,那就定义这个函数:
fun randomImage(): Path = pictures.sample()

== 应用的辅助函数部分:

+ 需要到用户配置环境变量的部分递归找图像文件,那就抽象成
fun indexImage(path: Path)

+ 递归找图像的时候需要一个目录作为起始点,并且必须首先检查它是目录,就抽象成
fun checkImagePath(parentPromise: Future<*>?): Path?

+ 递归找图像需要判断一个文件是不是图像,使用正则表达式判断文件扩展名
object Helper { internal fun isImageFile(f: File) = ACCEPTABLE_REGEX.matches(f.name) }

== 其他:

+ 递归寻找的时候需要计时间,不如泛化一下,允许传入一个函数来执行『计时』的操作

private fun withTimeLog(name: String, op: () -> String?)
private fun withTimeLog(name: String, desc: String) = withTimeLog(name) { desc }

== API:

vertx 的包:

import io.vertx.core.*
import io.vertx.ext.web.*

创建 HttpServer:vertx.createHttpServer()
创建 URL 路由:Router.router(vertx)
新建 URL 路径:Router#route(HttpMethod, String)::handler(Function)
设置服务路由:HttpServerr#requestHandler(Router)
HttpServer 监听:HttpServer#listen(Port, ParentFuture)
index 的实现使用了 Kotlin 扩展的 FileTreeWalker
duangsuse::Echo
index 的实现使用了 Kotlin 扩展的 FileTreeWalker
其实说简单一点,还可以这么定义:

fun scanImageFiles(fromDir: File) {
val (added, ignored) = fromDir.walk().partition(Helper::isImageFile)

picturePathes.addAll(added.map(File::getAbsolutePath))

logger.warn("${added.size} images added, ${ignored.size} plain files ignored")
}
啊真是傻逼死了,我作为一个编译原理爱好者居然在这种已经完成了的事情上多花了这么多时间!难道这些时间不应该拿来写解释器...

最近刚想到 Dynamic Scoping 和 Lexical Scoping 怎么写
duangsuse::Echo
我待会把坑填完... #Android #blogPOst https://blog.yuuta.moe/2017/07/29/begin-dir/ 欸,Yuuta 的 Dir 在 17 年就开始了? 还是元旦? 原来 Yuuta 在我开发第一个应用之前就有作品? 🤔 WTF 我以为 Dir 是 18 年出的...
既然提到了 Yuuta 鱼塔大佬,那我就给你们快速了解一下鱼塔的博客

https://blog.yuuta.moe

我所认为所有有干货(技术上的信息)的博文,如下:

== JavaEE
https://blog.yuuta.moe/2017/05/30/webservlet-jetty-appserver/
这篇博文《WebServlet+Jetty+Nginx轻松开发并部署应用服务器》是讲 Java Servlet 架构后端服务器 + Jetty 应用服务器 + Maven 开发 Http 服务端应用的

文章使用了 IntelliJ IDEA Community 作为演示 IDE、Maven 作为自动构建和依赖管理系统(J2EE 最令人头疼的事情来了:XML,一大堆名字... 还必须得填,如果忘了还得想,哪些属性还没设置呢...)

应用程序的 classpath 是由 maven Jetty 插件管理的,使用了 lifecycle:jetty:run
应用程序的调试是 IDEA 远程调试,这个讲了一些

servlet 的东西就不用说了,想必都能默写出来,后面会有精简手册。

Abstract:
我最近需要为 Dir 开发后端应用服务器,以前是用的某SaaS服务平台(也是WebServlet),觉得太贵,于是需要部署到自己的服务器。目前有比较成熟的 Python 、PHP 和 JavaScript等语言 可用,但是我需要尽快开发出来,不能花时间新学一门语言,于是就选择了一直在用的 WebServlet。

== Android
https://blog.yuuta.moe/2017/05/05/use-app_process/

使用 app_process (Android DalvikVM 的前端,Zygote client)
举了个 Kill.java (用 Android Privileged Activities API 杀 CoolMarket)栗子
教了大家不使用 IDE 的 Android/Java 命令行工具开发

https://blog.yuuta.moe/2017/09/12/new-way-access-hidden-api/

Android SDK 有些不允许使用的内部 API(Hidden API)
这些 API 没有在官方 android.jar 接口包里定义,并且,现在还不允许直接使用 Java 反射使用这些接口(虚拟机上做了检查,black-grey List)
(谈到 Android.jar,也顺带了解一下 Gradle 的 implementationcompile 有啥区别吧)(你的应用依赖的库,他们不管依赖什么都不会影响到你的应用,反观 compile 则会让你的项目传递性依赖他们所依赖的东西)

就是说使用替换 Android.jar 的方式啦。

至于可不可能,因为运行时 Android 设备上是有这些类/方法的,不会找不到(但也有可能没有,所以如果这么 Hack,不能被 javac 的无报错迷惑,为了程序健壮性写好 catch finally 块)。
但是,因为我不知道到底是什么情况,到底具体捕捉那种 Exception 不清楚,自己查字节码(比如,invokevirtual

说到这里,继续科普一下 JVM 1.7 时候的一些 invoke* 指令:

(后面跟的都是用途之一而已)
invokestatic:调用静态方法
invokespecial:调用构造器
invokeinterface:寻找调用某接口抽象方法的实现
invokevirtual:调用虚方法(很多时候『非静态』方法都是虚的,Kotlin 里面很多方法都不是虚方法 — 只有 open 的方法可以被复写以支持子类型多态)

JVM 1.8 的时候加入了特别的 invokedynamic 允许用户代码协作 JVM 进行方法查找
这也实现了 Lambda(因为要使用 LambdaFactory 为指定接口创建实例对象),因为 DalvikVM 没有增添此方法,Android Dexer 使用 RuntimeDesugar 反射解决 Lambda 对象生成的问题。

顺便科普一下,Kotlin 和 Java 8 都支持『SingleAbstractMethod』单抽象方法 Lambda
也即:
abstract class Invokable<T> { @FunctionalInterface T invoke(); }
static <T> T doInvoke(Invokable f) { return f.invoke(); }
//...
Invokable fn = new Invokable<Void>(() -> System.out.println("Invokable invoked"));
doInvoke(fn); // Invokable invoked
但是不允许 Lambda 实现 SAM 接口,只能实现抽象类。

https://blog.yuuta.moe/2017/07/10/zygote-appprocess-init/

你们不要被 Trumeet 放在上面的那张图迷惑了,其实这篇文章的内容很简单,也不包含流程分析。

简单介绍了一下 Zygote 和 /sbin/init 的关系,app_process 是什么

贴了 zygote RunCommand service 的代码

https://blog.yuuta.moe/2018/12/10/optimize-docker-image-by-using-multi-stage-building/

这个我之前说过,看这里

https://blog.yuuta.moe/2017/11/10/from-vibrator-to-system-service/

待会会讲,谈到了 Android Service 的架构,并且实现了一个『需要特权』的 Service

大概是这样的:


[outsider] OOServer
^
| AIDL IPC / IBinder
OOService [协调 C/S] IOOServeice (Stub.asInterface)
^
|
OO

此外还有 OOManager 和 SeviceResgistry 这种东西,待会画图

https://blog.yuuta.moe/2017/07/10/appprocess-uid/
简单的知识点科普,不到半面可以速看:

app-process 与 内部运行的Java 程序的UID是如何决定的 呢..

+ 使用 Root 执行 app_process 可行,进程 UID 是 Root
+ 使用 ADB,则 UID 是 Shell
+ 使用普通应用,则 UID 是应用的 UID u*_a*

也就是说 app_pocess 内的Java程序是和启动者的UID一致,而不是只允许Shell/Root调用app_process(
普通应用启动,UID也是普通应用的,想获取一些系统权限照样是不行的,保障了安全(

详情可以自己找资料了解 UNIX 进程权限系统,这个很好记。
不过对 Java 应用来说,并没有一个所谓的『进程』来运行它,它的线程们独占整个虚拟机,而虚拟机就代表了『Java 程序』的操作系统视角
做系统调用的话,检查的也是 Calling VM process 的权限,很好理解的,和 Bash Shell 解释器 fork 子进程是一个道理



———
最后总结一下最值得一看的文章:

⭐️https://blog.yuuta.moe/2017/11/10/from-vibrator-to-system-service/
⭐️https://blog.yuuta.moe/2017/05/30/webservlet-jetty-appserver/
⭐️https://blog.yuuta.moe/2017/05/05/use-app_process/

是贴了不少代码的
方式选错了... #KDE
正确的打开方式:
Vibrator.svg
24 KB
Vibrator.png
255.5 KB
对应的位图 #Share #Android #svg
Vibrator.svg
27.8 KB
最后完整注释的版本 #Android
duangsuse::Echo
最后完整注释的版本 #Android
This media is not supported in your browser
VIEW IN TELEGRAM
睡觉睡觉,我可懒得老是管 XML 和几个接口/抽象类定义的事情...

CachedServiceFetcher、registerService、permission-group、checkSelfOrCallingPermission 什么的,你们自己看吧,给张图就跑~
This media is not supported in your browser
VIEW IN TELEGRAM
因为 Telegram 一直连不上,白白浪费了很多时间!
一个小时是有的
This media is not supported in your browser
VIEW IN TELEGRAM