initial commit
This commit is contained in:
commit
92dc248455
|
@ -0,0 +1,10 @@
|
|||
INSTALLDIR=/run/media/nico/KOBOeReader/.adds/gemini
|
||||
|
||||
all: kobo-gemini update
|
||||
|
||||
kobo-gemini:
|
||||
CGO_ENABLED=1 GOARCH=arm CC=arm-kobo-linux-gnueabihf-gcc CXX=arm-kobo-linux-gnueabihf-g++ go build
|
||||
|
||||
update: kobo-gemini run.sh nickel.sh
|
||||
cp kobo-gemini run.sh nickel.sh ${INSTALLDIR}
|
||||
chmod a+x ${INSTALLDIR}/*
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
CGO_ENABLED=1 GOARCH=arm CC=arm-kobo-linux-gnueabihf-gcc CXX=arm-kobo-linux-gnueabihf-g++ go build
|
|
@ -0,0 +1,13 @@
|
|||
module tildegit.org/nihilazo/kobo-gemini
|
||||
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
git.sr.ht/~adnano/go-gemini v0.1.13
|
||||
github.com/fogleman/gg v1.3.0
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/shermp/go-fbink-v2 v1.20.2
|
||||
github.com/shermp/go-fbink-v2/v2 v2.21.0
|
||||
github.com/shermp/go-kobo-input v0.0.0-20180928074949-be0734a2dcc6
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
git.sr.ht/~adnano/go-gemini v0.1.13 h1:vzKkkVrOzMpfJ1AAeE/PChg0Rw5Zf+9HrnwsgVxXUT4=
|
||||
git.sr.ht/~adnano/go-gemini v0.1.13/go.mod h1:If1VxEWcZDrRt5FeAFnGTcM2Ud1E3BXs3VJ5rnZWKq0=
|
||||
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/shermp/go-fbink-v2 v1.20.2 h1:EtRKDZwrc8fkNGDZppsYB2nxcMosYU7hqYLovMP78/4=
|
||||
github.com/shermp/go-fbink-v2 v1.20.2/go.mod h1:88bOAwruwze/4JB/KW8uoyPtWm5OPa1BZEraFMHJgpQ=
|
||||
github.com/shermp/go-fbink-v2/v2 v2.21.0 h1:S2Q8B5zLGo7xTGILpqkVNZB94YwkehvTmECIYkxKH04=
|
||||
github.com/shermp/go-fbink-v2/v2 v2.21.0/go.mod h1:QPZ+LtEGpr7FkAwfS1AuCHXUrTJWg57PKRl4SmnzKak=
|
||||
github.com/shermp/go-kobo-input v0.0.0-20180928074949-be0734a2dcc6 h1:Tf6xr3SyROl/gYEbLVVRoASIuehPrjzq1y3P7krVqlo=
|
||||
github.com/shermp/go-kobo-input v0.0.0-20180928074949-be0734a2dcc6/go.mod h1:DuK6sbQLR5V3MLqWS8y+wYaFj4KIyPeNMe5HrOgRH2w=
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI=
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
tildegit.org/nihilazo/go-kobo-input v0.0.0-20210121201215-df5621661ac7 h1:7VnVnqyc+wmztFdkwujdIdjAEEmpAta2xGv/bvLZMXQ=
|
Binary file not shown.
|
@ -0,0 +1,149 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
//"github.com/fogleman/gg"
|
||||
"github.com/shermp/go-fbink-v2/gofbink"
|
||||
"github.com/shermp/go-kobo-input/koboin"
|
||||
//"image"
|
||||
"git.sr.ht/~adnano/go-gemini"
|
||||
"git.sr.ht/~adnano/go-gemini/tofu"
|
||||
"crypto/x509"
|
||||
// "time"
|
||||
// "bytes"
|
||||
"errors"
|
||||
"net/url"
|
||||
"bufio"
|
||||
"io/ioutil"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
hosts tofu.KnownHosts
|
||||
hostsfile *tofu.HostWriter
|
||||
scanner *bufio.Scanner
|
||||
)
|
||||
|
||||
var height int = 1080
|
||||
var width int = 1440 // TODO get from device instead of hardcoding
|
||||
|
||||
func trustCertificate(hostname string, cert *x509.Certificate) error { // TODO actually check certs
|
||||
/*host := tofu.NewHost(hostname, cert.Raw, cert.NotAfter)
|
||||
knownHost, ok := hosts.Lookup(hostname)
|
||||
if ok && time.Now().Before(knownHost.Expires) {
|
||||
// Check fingerprint
|
||||
if bytes.Equal(knownHost.Fingerprint, host.Fingerprint) {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error: fingerprint does not match!")
|
||||
}
|
||||
return errors.New("error: fingerprint does not match!")*/
|
||||
return nil
|
||||
}
|
||||
|
||||
func do(req *gemini.Request, via []*gemini.Request) (*gemini.Response, error) {
|
||||
client := gemini.Client{
|
||||
TrustCertificate: trustCertificate,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
switch resp.Status.Class() {
|
||||
case gemini.StatusClassInput: // TODO implement input
|
||||
/* input, ok := getInput(resp.Meta, resp.Status == gemini.StatusSensitiveInput)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
req.URL.ForceQuery = true
|
||||
req.URL.RawQuery = gemini.QueryEscape(input)
|
||||
return do(req, via) */
|
||||
|
||||
|
||||
case gemini.StatusClassRedirect:
|
||||
via = append(via, req)
|
||||
if len(via) > 5 {
|
||||
return resp, errors.New("too many redirects")
|
||||
}
|
||||
|
||||
target, err := url.Parse(resp.Meta)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
target = req.URL.ResolveReference(target)
|
||||
redirect := *req
|
||||
redirect.URL = target
|
||||
return do(&redirect, via)
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Framebuffer setup
|
||||
fbinkOpts := gofbink.FBInkConfig{}
|
||||
rOpts := gofbink.RestrictedConfig{}
|
||||
fb := gofbink.New(&fbinkOpts, &rOpts)
|
||||
fb.Open()
|
||||
defer fb.Close()
|
||||
fb.Init(&fbinkOpts)
|
||||
fb.ClearScreen(&fbinkOpts)
|
||||
fb.Refresh(0,0,0,0, gofbink.DitherPassthrough, &fbinkOpts)
|
||||
|
||||
// Touchscreen setup
|
||||
touchPath := "/dev/input/event1"
|
||||
t := koboin.New(touchPath, height, width)
|
||||
if t == nil {
|
||||
return
|
||||
}
|
||||
defer t.Close()
|
||||
|
||||
// Load known hosts file
|
||||
path := "/mnt/onboard/.adds/gemini/known-hosts"
|
||||
err := hosts.Load(path)
|
||||
if err != nil {
|
||||
fb.Println(err)
|
||||
time.Sleep(1000)
|
||||
}
|
||||
|
||||
hostsfile, err = tofu.NewHostsFile(path)
|
||||
if err != nil {
|
||||
fb.Println(err)
|
||||
time.Sleep(1000)
|
||||
}
|
||||
|
||||
url := "gemini://breadpunk.club/~bagel"
|
||||
req, err := gemini.NewRequest(url)
|
||||
if err != nil {
|
||||
fb.Println(err)
|
||||
time.Sleep(1000)
|
||||
}
|
||||
resp, err := do(req, nil)
|
||||
if err != nil {
|
||||
fb.Println(err)
|
||||
time.Sleep(1000)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Handle response
|
||||
if resp.Status.Class() == gemini.StatusClassSuccess {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
fb.Println(err)
|
||||
}
|
||||
fb.Println(string(body))
|
||||
} else {
|
||||
fb.Println(fmt.Sprintf("%d %s\n", resp.Status, resp.Meta))
|
||||
}
|
||||
|
||||
for {
|
||||
x, y, err := t.GetInput()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if x < 100 && y < 100 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
#!/bin/sh
|
||||
# This script is from koreader under AGPL-v3
|
||||
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/lib:"
|
||||
|
||||
# We don't need to duplicate any of the env setup from rcS, since we will only ever run this to *restart* nickel, and not bootstrap it.
|
||||
# Meaning we've already got most of the necessary env from nickel itself via both our launcher (fmon/KFMon) and our own startup script.
|
||||
# NOTE: LD_LIBRARY_PATH is the only late export from rcS we don't siphon in koreader.sh, for obvious reasons ;).
|
||||
export LD_LIBRARY_PATH="/usr/local/Kobo"
|
||||
|
||||
# Reset PWD, and clear up our own custom stuff from the env while we're there, otherwise, USBMS may become very wonky on newer FW...
|
||||
# shellcheck disable=SC2164
|
||||
cd /
|
||||
unset OLDPWD
|
||||
unset LC_ALL TESSDATA_PREFIX STARDICT_DATA_DIR EXT_FONT_DIR
|
||||
unset KOREADER_DIR KO_DONT_GRAB_INPUT
|
||||
|
||||
# Ensures fmon will restart. Note that we don't have to worry about reaping this, nickel kills on-animator.sh on start.
|
||||
(
|
||||
if [ "${PLATFORM}" = "freescale" ] || [ "${PLATFORM}" = "mx50-ntx" ] || [ "${PLATFORM}" = "mx6sl-ntx" ]; then
|
||||
usleep 400000
|
||||
fi
|
||||
/etc/init.d/on-animator.sh
|
||||
) &
|
||||
|
||||
Make sure we kill the Wi-Fi first, because nickel apparently doesn't like it if it's up... (cf. #1520)
|
||||
NOTE: That check is possibly wrong on PLATFORM == freescale (because I don't know if the sdio_wifi_pwr module exists there), but we don't terribly care about that.
|
||||
if grep -q "sdio_wifi_pwr" "/proc/modules"; then
|
||||
killall -q -TERM restore-wifi-async.sh enable-wifi.sh obtain-ip.sh
|
||||
cp -a "/etc/resolv.conf" "/tmp/resolv.ko"
|
||||
old_hash="$(md5sum "/etc/resolv.conf" | cut -f1 -d' ')"
|
||||
if [ -x "/sbin/dhcpcd" ]; then
|
||||
env -u LD_LIBRARY_PATH dhcpcd -d -k "${INTERFACE}"
|
||||
killall -q -TERM udhcpc default.script
|
||||
else
|
||||
killall -q -TERM udhcpc default.script dhcpcd
|
||||
fi
|
||||
# NOTE: dhcpcd -k waits for the signalled process to die, but busybox's killall doesn't have a -w, --wait flag,
|
||||
# so we have to wait for udhcpc to die ourselves...
|
||||
# NOTE: But if all is well, there *isn't* any udhcpc process or script left to begin with...
|
||||
kill_timeout=0
|
||||
while pkill -0 udhcpc; do
|
||||
# Stop waiting after 5s
|
||||
if [ ${kill_timeout} -ge 20 ]; then
|
||||
break
|
||||
fi
|
||||
usleep 250000
|
||||
kill_timeout=$((kill_timeout + 1))
|
||||
done
|
||||
|
||||
new_hash="$(md5sum "/etc/resolv.conf" | cut -f1 -d' ')"
|
||||
# Restore our network-specific resolv.conf if the DHCP client wiped it when releasing the lease...
|
||||
if [ "${new_hash}" != "${old_hash}" ]; then
|
||||
mv -f "/tmp/resolv.ko" "/etc/resolv.conf"
|
||||
else
|
||||
rm -f "/tmp/resolv.ko"
|
||||
fi
|
||||
wpa_cli terminate
|
||||
[ "${WIFI_MODULE}" != "8189fs" ] && [ "${WIFI_MODULE}" != "8192es" ] && wlarm_le -i "${INTERFACE}" down
|
||||
ifconfig "${INTERFACE}" down
|
||||
# NOTE: Kobo's busybox build is weird. rmmod appears to be modprobe in disguise, defaulting to the -r flag...
|
||||
# But since there's currently no modules.dep file being shipped, nor do they include the depmod applet,
|
||||
# go with what the FW is doing, which is rmmod.
|
||||
# c.f., #2394?
|
||||
usleep 250000
|
||||
rmmod "${WIFI_MODULE}"
|
||||
|
||||
if [ -n "${CPUFREQ_DVFS}" ]; then
|
||||
echo "0" >"/sys/devices/platform/mxc_dvfs_core.0/enable"
|
||||
# Leave Nickel in its usual state, don't try to use conservative
|
||||
echo "userspace" >"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
|
||||
cat "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq" >"/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"
|
||||
fi
|
||||
usleep 250000
|
||||
rmmod sdio_wifi_pwr
|
||||
fi
|
||||
|
||||
unset CPUFREQ_DVFS CPUFREQ_CONSERVATIVE
|
||||
|
||||
# Recreate Nickel's FIFO ourselves, like rcS does, because udev *will* write to it!
|
||||
# Plus, we actually *do* want the stuff udev writes in there to be processed by Nickel, anyway.
|
||||
rm -f "/tmp/nickel-hardware-status"
|
||||
mkfifo "/tmp/nickel-hardware-status"
|
||||
|
||||
# Flush buffers to disk, who knows.
|
||||
sync
|
||||
|
||||
# Handle the sdcard:
|
||||
# We need to unmount it ourselves, or Nickel wigs out and shows an "unrecognized FS" popup until the next fake sd add event.
|
||||
# The following udev trigger should then ensure there's a single sd add event enqueued in the FIFO for it to process,
|
||||
# ensuring it gets sanely detected and remounted RO.
|
||||
if [ -e "/dev/mmcblk1p1" ]; then
|
||||
umount /mnt/sd
|
||||
fi
|
||||
|
||||
# And finally, simply restart nickel.
|
||||
# We don't care about horribly legacy stuff, because if people switch between nickel and KOReader in the first place, I assume they're using a decently recent enough FW version.
|
||||
# Last tested on an H2O & a Forma running FW 4.7.x - 4.25.x
|
||||
/usr/local/Kobo/hindenburg &
|
||||
LIBC_FATAL_STDERR_=1 /usr/local/Kobo/nickel -platform kobo -skipFontLoad &
|
||||
[ "${PLATFORM}" != "freescale" ] && udevadm trigger &
|
||||
|
||||
return 0
|
Reference in New Issue