serverless の設定で簡単なロジックを含める
stage とかに応じて設定を変える方法があったのでいじってみます、${opt:stage}
とかよりもっと複雑なことしたくなったときに使えると思います: https://www.serverless.com/framework/docs/providers/aws/guide/variables/#exporting-a-function
なんとなく TypeScript でテンプレート作成しました
sls create -t aws-nodejs-typescript -p serverless-demo
import type { AWS } from '@serverless/typescript'; import hello from '@functions/hello'; const serverlessConfiguration: AWS = { ... custom: { hoge: "${file(./hoge.js)}", ... }, }; module.exports = serverlessConfiguration;
hoge: "${file(./hoge.js)}"
で hoge.js
に定義した関数を呼び出してくれるらしい
パラメータはどんな感じか見たいのでこんな感じの関数を書いた
module.exports = async (p) => { console.log(p) return {} }
serverless print
したらこんなの出てきた
{ options: [Object: null prototype] { format: null, path: null, transform: null, region: null, 'aws-profile': null, app: null, org: null, 'use-local-credentials': null, config: null, stage: null, param: null, help: null, version: null, verbose: null, debug: null }, resolveConfigurationProperty: [AsyncFunction: resolveConfigurationProperty], resolveVariable: [AsyncFunction: resolveVariable] }
で hoge: "${file(./hoge.js)}"
は hoge: {}
として解決されていた
感想
stage
とか手に入るので、環境毎に何か変えるとかに使えそう、定期実行関数のスケジュールを開発環境では少なくしておくとか。resolveXXX
系の関数で設定から値を持ってくることもできるfile
の実体、多分ここっぽいのだけど typescript は対応してなさそう?: https://github.com/serverless/serverless/blob/8dae21375801be00f24d68d6a3e12854132b7bb9/lib/configuration/variables/sources/file.js#L58serverless print
が知れてよかった。諸々 resolve された状態を出してくれるコマンド
javascript の ArrayBuffer
なんとなく javascript の ArrayBuffer 触っている。データをストリームで処理することが自分は好きなのかもしれないって最近思って、テキストは特にすることがないのでバイトデータ、という感じで。
とりあえず jpeg からサイズ情報が取れる程度のパーサーを実装してみた。GPS は取れるかどうか試していない。サーバでもブラウザでも使えるように tsconfig を調整したりやや勉強になった。(TypeScript で書いている時に import ... from './xxx/xxx.js' みたいに書くの新鮮な違和感だった)
png, zip とか pdf もちょっとずつ処理できるようにしたいなと思ったりしている。これらがなんかプロダクトにつながってくれればいいけど、今のところあまり考えられていない。
サーバとブラウザでも使えるようにした理由として、サービスワーカー上でも使えて、必要に応じてサーバでも処理できるようなものを書きたいと思ったから (fetch イベントを状況に応じて切り替える感じ)。電波の貧弱な国に少しいたのでブラウザでできることはブラウザでやってしまいたいというのが理由の背景となる体験だと思う。ちょっとファイルを加工するくらいの処理ならブラウザでやってしまった方が費用の面でも安くなるだろうし。
他のデータ形式追加していくのもいいけど、プロダクトに繋がるものがモチベーション保てていいなとも思う。RFB protocol とかも楽しいかもしれないけど、ちょっと昔書いて挫折した記憶がある、状態遷移を上手く扱えなかった感じ (A メッセージを受け取ったら B モードに移行して C メッセージを待つ、みたいな部分が雑だった)。
とりあえずプロトコルとかデータ形式を羅列してみて、面白そうで何か作れそうなやつを考えるのがいいかもしれない。
ブログを放置しすぎてしまっているのが気になって久々に書いてみた。
Deno で簡単な重複行削除スクリプトを書いた
ファイルの重複行削除がしたかったのでスクリプトを書こうと思ったのですが、せっかくだし Deno で書いてみることにしました。
https://github.com/ushumpei/scripts/blob/main/remove_duplicate_lines.ts
import { iter } from "https://deno.land/std@0.93.0/io/util.ts"; const N = Deno.env.get("NEWLINE") || "\n"; export type M = { b: boolean; d: string[]; h: { [k: string]: boolean }; }; const i = Deno.args[0]; const o = Deno.args[1]; const f: Deno.File = Deno.openSync(i, { read: true }); const m: M = { d: [], h: {}, b: false }; const t: string = await Deno.makeTempFile(); let r = ""; for await (const ck of iter(f)) { const ls = (r + new TextDecoder().decode(ck)).split(N); r = ls[ls.length - 1]; const ot = ls .slice(0, -1) .reduce((_m: M, l: string) => { if (!_m.h[l]) { _m.h[l] = true; _m.d.push(l); } return _m; }, m) .d.join(N); if (ot.length === 0) continue; const of = new TextEncoder().encode(m.b ? N + ot : ot); Deno.writeFileSync(t, of, { append: true }); m.d = []; m.b = true; } f.close(); Deno.copyFileSync(t, o);
github にあげていて、こんな感じで URL 指定でも実行できます。
$ deno run --allow-env --allow-read --allow-write \ > https://raw.githubusercontent.com/ushumpei/scripts/main/remove_duplicate_lines.ts \ > 入力ファイル名 \ > 出力ファイル名
感想
groovy
のようにライブラリのインポート含めてスクリプトが一枚のファイルで完結するので、結構楽でいいです。しかも URL 指定でインポートできるのでより手軽。なので書くときにインポートするものをちゃんと精査しないといけないと思います。--allow-net
などオプションで権限が指定できるので、その辺もしっかり吟味していきたいです。(権限つけ忘れた時のエラー文がわかりやすいのも良い感じ)- 書いたスクリプトで宣言している変数名は一文字とかばかりなのですが、なんかテンション上がって極力短くしてみました。楽しかった。
- 環境変数による改行コードの指定は未テストで、いらないんじゃないかなーと思っています。
--allow-env
も消せるしそうしたい気がしてきた。 - メモリに一気に乗せないように書いたつもりだけどどうなんだろう。
- 既出行を格納しているオブジェクトが巨大になって死ぬとかありそう。
- あと
copyFileSync
は中身をみていないけどちょろちょろコピーしてくれるのだろうか? - あとこれ
TransformStream
で描き直したい。
Deno
のvscode
拡張入れた後上手く設定できてなくてcannot find name Deno
とか言われてたけどコマンドパレットからDeno: Initialize Workspace Configuration
実行したらなんか上手くいった。- 無限インポートループとかどうなるんだろうか。
- https://doc.deno.land/builtin/stable 見て書いた。
- Deno Deploy はまだちゃんと触っていない、リクエスト処理は
fetch
イベントのハンドラー書いてやるみたいだけど、ローカルだと発火しなくてちょっと手間取った、なんか公開してくださっているライブラリ入れたら動いた。https://deno.land/x/fetch_event_adapter/listen.ts
WordPress で独自の rss フィードを設定する
意外に簡単だったけど忘れそうなのでメモ。 functions.php
に以下を記述
<?php add_action('init', function() { add_feed('custom', function() { header('Content-Type: application/rss+xml'); include_once 'custom_feed.php'; }); });
デフォルト?だと サイトURL?feed=custom
で custom_feed.php
の中身が返ってくるようになる。でも WordPress から「ちゃんとした xml じゃない!」みたいな怒られ方するので、custom_feed.php
を作るのがまた一苦労な感じだと思いました。正しい feed 生成方法とかあるのだろうか。
感想
WordPress いじるときは wp-env
と言う WordPress ローカル環境を立ち上げてくれる npm ライブラリを使っていてなかなか快適です。思い出したけど Feedly 整理しなければいけない。
Java でストリームの末尾数行を捨てる
末尾の行を捨てるためには一旦ファイルを全部読まなきゃいけないかと思ったけど、捨てたい行数を先読みしておけば良いという感じでした。
import java.io.*; import java.util.LinkedList; import java.util.Queue; // ファイルの末尾数行捨てる BufferedReader class TailIgnoringBufferedReader extends Reader { private final BufferedReader _reader; private final int num; Queue<String> queue = new LinkedList<>(); TailIgnoringBufferedReader(Reader in, int num) { this._reader = new BufferedReader(in); this.num = num; } public String readLine() throws IOException { while (this.queue.size() <= this.num) { String line = this._reader.readLine(); if (line == null) return null; this.queue.add(line); } return this.queue.poll(); } @Override public int read(char[] cbuf, int off, int len) throws IOException { return this._reader.read(); } @Override public void close() throws IOException { this._reader.close(); } }
( lines
とかは未実装。BufferedReader と名付けていいかは微妙なところかも。)
こんな感じで使えます
InputStream data = new ByteArrayInputStream("1\n2\n3\n4\n5\n6\n7\n8\n9".getBytes()); try (TailIgnoringBufferedReader reader = new TailIgnoringBufferedReader(new InputStreamReader(data), 5)) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); }
先頭も捨てられるようにすれば任意の切り出し方ができるようになる
感想
InputStream 系のコードは書いていて楽しい
read
とかでも対応するにはどうするべきなんだろうか?(先読みは同じで、 currentLine
みたいなインスタンス変数持ってそこから返していく、空になったら Queue からロードする感じかな)