群晖 NAS - frp 使用及实现 Mac 远程访问

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。 一、服务端配置 1、安装及配置 这里以群晖 NAS 为例: 在 Docker 注册表里搜索 frps,安装 latest 版本(也可以安装指定版本); 在映像里创建容器,并进入高级设置; 在高级设置里启用自动重新启动; 在存储空间添加文件,装载路径为 /etc/frp/frps.ini; 网络里勾选使用与 Docker Host 相同的网络; 启动容器。 2、frps.ini 配置文件 [common] bind_port = 7000 token = your_token dashboard_port = 7500 dashboard_user = your_dashboard_user dashboard_pwd = your_dashboard_pwd vhost_http_port = 8000 vhost_https_port = 8001 二、客户端配置 1、安装及配置 同样以群晖 NAS 为例,安装及配置基本跟服务端相同,配置文件改为 frpc.ini 即可。 2、frpc.ini 配置文件 [common] server_addr = your_server_addr server_port = 7000 tls_enable = true token = your_token [ssh] type = tcp local_ip = 192....

July 8, 2022 · Darren Ou

Mac 装机必备

开发工具 iTerm2 iTerm2 is a terminal emulator for macOS that does amazing things. Tabby Tabby is an infinitely customizable cross-platform terminal app for local shells, serial, SSH and Telnet connections. Fig Fig adds VSCode-style autocomplete to your existing terminal. 终端自动补全工具,能在终端里有 VSCode 的自动补全体验,支持 iTerm2。如果你使用的是 zsh,也可以安装 zsh-autosuggestions 作为补充使用。 Homebrew The Missing Package Manager for macOS. Oh My Zsh Oh My Zsh is an open source, community-driven framework for managing your ### zsh configuration....

December 20, 2021 · Darren Ou

macOS 解决 App Nap 导致 Timer 回调变慢问题

背景 在开发 macOS 上的窗口共享过程中,发现 demo 被其它应用覆盖后,在25s左右,观众收到的窗口画面开始变得卡顿。 经过排查发现问题出在主播端的采集逻辑处。在我的上一篇文章 macOS 屏幕共享开发 提到,窗口共享的实现跟屏幕共享不一样,窗口共享没有现有的系统接口,需要启动一个 Timer 去定时对窗口截图,再对截图进行处理。 通过打印日志发现,demo 进入后台后,Timer 在25s左右,回调开始变慢,大约2s才回调一次,问题的原因就出在这里。 排查原因 为了避免其它逻辑影响了结果,新建一个干净的 demo。 我在窗口共享中用的是 GCD Timer,一开始猜测是 GCD Timer 的某些参数没有设置,查看文档后没找到相关的参数;然后猜测 GCD Timer 的问题,但是换成 NSTimer 后,发现也有一样的问题,这时候我开始猜测是系统导致的问题了。 开始查阅资料,发现了 一篇文章 里面提到: App Nap 是 OS X 10.9 Mavericks 的一项新功能。它能帮你在同时运行多个应用程序时节省电能。 这时候有了切入点,查询关键字 App Nap 就可以发现相关资料。 App Nap 附上苹果官方说明文档:Extend App Nap If an app isn’t performing user-initiated work such as updating content on screen, playing music, or downloading a file, the system may put the app in App Nap....

July 5, 2021 · Darren Ou

macOS 屏幕共享开发

一、屏幕录制权限 应用首次创建屏幕截图或者窗口截图时(以下任一接口都可以),就会显示系统的权限申请弹窗,通过选中Screen Recording里面的相关应用,重启应用后即可开启权限。 CGDisplayCreateImage() CGDisplayCreateImageForRect() CGWindowListCreateImage() CGWindowListCreateImageFromArray() 二、获取screenId 通过AppKit的NSScreen.screens或者通过CoreGraphics的CGGetActiveDisplayList()都可以获取当前的所有显示器信息,下面用NSScreen.screens举例子: [NSScreen.screens enumerateObjectsUsingBlock:^(NSScreen * _Nonnull screen, NSUInteger idx, BOOL * _Nonnull stop) { NSNumber *screenNumber = screen.deviceDescription[@"NSScreenNumber"]; if (screenNumber) { CGDirectDisplayID displayId = screenNumber.unsignedIntValue; NSLog(@"displayId: %d", displayId); } }]; 注意:如果是镜像显示,则只会打印一个显示器信息。 三、获取windowId 1、获取windowId列表 通过接口CGWindowListCopyWindowInfo()可以获取windowId列表。 其中kCGWindowListExcludeDesktopElements参数表示从列表中排除所有属于桌面元素的窗口。 CGWindowListCopyWindowInfo()返回的是一个CFArrayRef,使用完后需要主动release。 这里有一个技巧,利用CFBridgingRelease()函数,可以把CFArrayRef桥接到NSArray,并且会把内存管理转移到ARC,就是说我们不需要再去主动release了。 NSArray *windowDictArr = CFBridgingRelease(CGWindowListCopyWindowInfo(kCGWindowListOptionAll | kCGWindowListExcludeDesktopElements, 0)); 2、过滤无用windowId 通过以上接口获取到的windowId列表可能会包含很多我们不关心的windowId: 1. 没显示出来的window 通过kCGWindowLayer跟kCGWindowAlpha两个key,可以获取到当前window是否有layer以及是否透明,我们需要过滤掉不可见的window。 2. 过滤信息不全的window kCGWindowNumberkey可以从字典里获取到windowId,需要过滤没有windowId的字典信息。 3. 过滤无法获取截图的window 通过CGWindowListCreateImage()接口,传入对应windowId,可获取到window的截图,如果无法获取到截图,可能没有录屏权限、不是window主体、window不可见。 3、获取window frame 通过CGRectMakeWithDictionaryRepresentation()可获取窗口的frame,某些业务可能需要用到frame。 四、屏幕共享 屏幕共享的视频输入总体来说跟摄像头的视频输入相当类似,可以理解成视频流从摄像头改成了屏幕输入(AVCaptureDeviceInput->AVCaptureScreenInput),视频输出的处理则跟摄像头的输出处理完全一样。 1、关键代码: - (void)startCapture { self....

May 18, 2021 · Darren Ou