自言字语 - 独

自从上一篇博客,大概有一年多没有代表自己写过东西了吧。上了一年班忙忙碌碌,甚至工作总结也写得结结巴巴。领导催了几次,结果都不好意思再催了。连工作总结都没写完,还好意思写博客吗?结果前阵子瞄了一眼领导和另一位资深同事的博客,最近都没写什么东西,心里呵呵一笑却觉着有些悲哀。

直到进入了六月,突然意识到自己偷偷欣赏的人们都要毕业了,或是真正地在学校毕业,或是同事换了部门,刚数了数好像七个都不止了。“离职不是离世”,但总觉得错失了好多跟人打交道的机会,就有点伤心。

冥想盆要溢出了,那还是接一下好了。但愿这是个让我踏踏实实写点文字的机会吧,不过还是得时刻提醒自己,大家都很忙,没人会看的。看来三年了一点都没变啊。

诶,接上了我想了几个星期的这个话题,“独”。毕业了大概也是走向孤独的一条路,那就来自言字语吧。

继续阅读“自言字语 - 独”

有茬找茬该去根 / 离析

几个月前还有班上的时候,我在工单队列里看到了一张工单弹了出来。这是隔壁管网络安全部门的主管申请 Adobe CC 授权的请求。

我校处理这些请求,都是靠工单、然后客服人工把用户名输到一个已经很成熟的、部门自己做的系统里,自动判断可以给的授权然后生成,只有客服主管才能强制覆盖生成授权的参数。我也不是很懂,他们为什么不把这个流程做成全自动工单,估计是没“资源”吧。

我的同事处理这张工单的时候,也没仔细看那位网安主管写了什么,就直接把用户名输了进去,因为那位主管似乎在学校选了课,系统会自动给他激活学生授权。然后网安主管回了封邮件,问我们说这个授权怎么用,他部门有个职工需要用这个授权。 继续阅读“有茬找茬该去根 / 离析”

给 HAProxy 增加第三方登录保护

HAProxy 作为一个非常强大且高效的负载均衡软件,真的是想做啥都可以了。最近就比较头疼某个很多人使用的 SSH 端口整天被人扫,想做一个动态 IP 白名单。顺着这个思路下去,就做了一个 HAProxy 的第三方登录保护的方案出来。

SSH 端口的保护

由于 SSH 协议的鉴权通常没法做到 reject,我也不大想去研究协议的细节,于是就准备直接从 4 层 TCP 的位置去保护。HAProxy 端想做一个动态白名单,本来是想用 acl file list 实现的,然后发现只有收费版 HAProxy 才有一个定时重载文件列表的模块 lb-update。看了看 HAProxy 的管理接口似乎可以实现动态维护 acl 列表,于是准备写一个小的 Web 应用去维护这个列表。

仔细看了看这个接口,似乎还有一个 table 的特性更符合需求,还可以动态记录访问次数什么的,于是就搞起来了。 继续阅读“给 HAProxy 增加第三方登录保护”

Wrap Context Manager (as nested) in a Python function

To make my code more elegant, I need to wrap a context manager with initialization code as a function in Python. This is definitely possible, but it took me some time to find the most elegant way to do this.

Generally speaking, you will want to enter all contexts when using the decorator @contextlib.contextmanager or @contextlib.asynccontextmanager. When the end user uses with my_function() as a:, everything inside the with block has been inside the nested contexts. When Python gets out of the end user's with block, it should also run all related __exit__s in the wrapper function. See example (requires Python 3.7+ probably and writes test.txt; you can test it on repl.it):

import asyncio
import contextlib
import aiofiles
import typing

@contextlib.asynccontextmanager
async def my_context_manager() -> typing.ContextManager[aiofiles.threadpool.AsyncFileIO]:
    # init
    filename = 'test.txt'

    async with aiofiles.open(filename, 'w+') as file:
        # you can still override or interact with `file` if needed
        yield file

async def main():
    # end user
    myfile: aiofiles.threadpool.AsyncFileIO
    async with my_context_manager() as myfile:
        print(await myfile.write("12\n"))
        await myfile.seek(0)
        print(await myfile.readline())

asyncio.run(main())

When I rewrite the code above I feel it so easy and natural. It really took me some time to realize how this works.

麻省理工的信息服务“客服”

最近听说,学校里有位新来的老师,登不上自己的学校邮箱,然后抱怨(翻译的版本俏皮了一些):

行吧,我试着在两个地方登录我的邮箱:(……),在哪边我都看不到登录页面。今日头条——都 9102 年了,电子邮件都已经 20 多年了。你们能不能招一些麻省理工的学生把你们的系统搞好……

不想评价这个老师的态度和“提问的智慧”(他的“建议”似乎也被自动忽略掉了),麻省理工的学生愿不愿意做这个工作也是个问号。不过我们可以类比一下,麻省理工自己的信息服务水平如何呢?他们会招“麻省理工的学生”吗? 继续阅读“麻省理工的信息服务“客服””

Side note of some scheduling tools

SignUpGenius

Free version includes:

  • multiple spots in one time slot
  • email (ics) confirmation to invitee
  • export as table
  • cancellation email triggered by organizer
  • modify bookings by unique link (in the email).

UX feels like oldest.

Doodle

Free version includes:

  • multiple spots in one time slot
  • export as table (maybe?)

No invitee email is available in free version. Booking modification can only be protected if invitees log in with a Doodle account. UX is a lot better.

Calendly

Free version includes:

  • email (ics) confirmation to invitee
  • export as table
  • cancellation email triggered by organizer
  • modify bookings by unique ID (in the email)

Paid version (10 days trial) includes:

  • multiple spots in one time slot
  • webhook (API)

UX is the best.

意想不到的「重设密码」挑战 / 理想园

去年我提了一嘴,现在在做一个客服的工作。不做不知道,电脑常识的下限真的让我永远想不到。

对方的提问常常让我反思,为什么会造成这种情况。作为一个技术员,换个角度看看普通人的操作,其实对更友好的工程设计还是挺有帮助的。

这一篇,来看个似乎简单、但不少人会有奇奇怪怪的问题的业务:「重设密码」。以下提到的虚构问题,基本上都有真实案例支撑,毕竟生活比故事更精彩。 继续阅读“意想不到的「重设密码」挑战 / 理想园”

Strip Assets Files in new Android Gradle

Spending 2 hours on this because 1) I don't have experience with Gradle script (its syntax looks funky) 2) DJI sxxks, and they put 50MB of large assets files to their SDK, which is camera distrotion_correction files that I never need, and 3) Android Gradle library upgrades, which deprecating mergeAssets.

Looking at some GitHub projects's Gradle script, it looks like dependsOn is very popular in defining what order the task should be executed, and it works! 继续阅读“Strip Assets Files in new Android Gradle”