Vaporの生みの親である Tanner が来日し参加してくれます。Vaporの紹介や他のプログラミング言語に比べる優位性、Vaporの未来や、USやヨーロッパでの浸透状況について話していただきます。
/// public var SERVER_MORE_RESULTS_EXISTS: MySQLStatusFlag = 0x0008
^ この辺の空のドキュメンテーションコメントが自動生成っぽい。NOW()
を使うのが間違ってる様に思える。 https://github.com/vapor/fluent/issues/464UTC_TIMESTAMP()
を使うべきでは。TIMESTAMP
カラムではなくDATETIME
カラムなのか。Swift.Date
はUTCですよね。vapor-clean
に、docker-compse
とHerokuの設定を追加したテンプレートを作った。 https://github.com/norio-nomura/vapor-cleanFuture
を表に出さない実装になってますね。rename
システムコールをまず試してダメだったら FileManager.moveItem
を試すというのをやったけど、corelibs-Foundationではそのケースが未実装なのかー。 https://github.com/Carthage/Carthage/pull/713 (edited)rename
使ってるのか(これはcontributionチャンス)root@7214eacbf30e:/var/vapor# swift a.swift Fatal error: enumerateSubstrings(in:options:using:) is not yet implemented: file Foundation/NSString.swift, line 791 /usr/bin/swift[0x3f24d54] /usr/bin/swift[0x3f25096] /lib/x86_64-linux-gnu/libpthread.so.0(+0x11390)[0x7f5a99805390] /usr/lib/swift/linux/libswiftCore.so(+0x2baf79)[0x7f5a94a43f79] /usr/lib/swift/linux/libswiftCore.so(_T0s17_assertionFailures5NeverOs12StaticStringV_SSAE4fileSu4lines6UInt32V5flagstF+0x2c)[0x7f5a948d646c] /usr/lib/swift/linux/libFoundation.so(+0x501c3f)[0x7f5a8dac7c3f] /usr/lib/swift/linux/libFoundation.so(+0x501b0a)[0x7f5a8dac7b0a] /usr/lib/swift/linux/libFoundation.so(_T010Foundation8NSStringC14enumerateLinesyySS_SpyAA8ObjCBoolVGtcF+0x77)[0x7f5a8db559c7] /usr/lib/swift/linux/libFoundation.so(_T0s14StringProtocolP10FoundationSS5IndexVADRtzrlE14enumerateLinesyySS_Sbztc8invoking_tF+0xa0)[0x7f5a8db6bed0] [0x7f5a99c350c3] /usr/bin/swift[0xfed1ce] /usr/bin/swift[0xff1692] /usr/bin/swift[0x4d9076] /usr/bin/swift[0x4c35d3] /usr/bin/swift[0x4beecc] /usr/bin/swift[0x4778c4] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f5a97f2f830] /usr/bin/swift[0x475179] Stack dump: 0. Program arguments: /usr/bin/swift -frontend -interpret a.swift -disable-objc-interop -color-diagnostics -module-name a Illegal instruction
(edited)root@7214eacbf30e:/var/vapor# swiftc a.swift root@7214eacbf30e:/var/vapor# ./a Fatal error: enumerateSubstrings(in:options:using:) is not yet implemented: file Foundation/NSString.swift, line 791 Illegal instruction
libunwind
.swift
コマンドだとswift
コマンドが設定したシグナルハンドラが受け取ってくれます。swiftc
で作成された成果物には、スタックトレースを出力するシグナルハンドラは設定されません。fatalError()
はシグナル経由ではなくて、fatalError()
> _assertionFailure()
> _swift_stdlib_reportFatalError*()
> swift_reportError()
> reportNow()
> printCurrentBacktrace()
なのかな。fatalError()
をユーザーコードで呼び出した場合は https://github.com/apple/swift/blob/master/stdlib/public/runtime/Errors.cpp#L275 のprintCurrentBacktrace()
が呼ばれ、NSUnimplemented()
経由だとprintCurrentBacktrace()
は呼ばれずシグナルハンドラの挙動に依存する、という違いがあると知りました。-assert-config
でコントロールできそうにも見える。 -assert-config <value> Specify the assert_configuration replacement. Possible values are Debug, Release, Unchecked, DisableReplacement.
(edited)fatalError()
Fatal error: file <stdin>, line 1 #0 0x0000000003f25074 PrintStackTraceSignalHandler(void*) (/usr/bin/swift+0x3f25074) #1 0x0000000003f253b6 SignalHandler(int) (/usr/bin/swift+0x3f253b6) #2 0x00007f662e570390 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x11390) #3 0x00007f6629e5a0b9 _T0s17_assertionFailures5NeverOs12StaticStringV_SSAE4fileSu4lines6UInt32V5flagstFTf4nxnnn_n (/usr/lib/swift/linux/libswiftCore.so+0x2bb0b9) #4 0x00007f6629cec41c _T0s17_assertionFailures5NeverOs12StaticStringV_SSAE4fileSu4lines6UInt32V5flagstF (/usr/lib/swift/linux/libswiftCore.so+0x14d41c) #5 0x00007f662e9a006e #6 0x0000000000fed3be llvm::MCJIT::runFunction(llvm::Function*, llvm::ArrayRef<llvm::GenericValue>) (/usr/bin/swift+0xfed3be) #7 0x0000000000ff1882 llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, char const* const*) (/usr/bin/swift+0xff1882) #8 0x00000000004d9076 swift::RunImmediately(swift::CompilerInstance&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, swift::IRGenOptions&, swift::SILOptions const&) (/usr/bin/swift+0x4d9076) #9 0x00000000004c35d3 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) (/usr/bin/swift+0x4c35d3) #10 0x00000000004beecc swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) (/usr/bin/swift+0x4beecc) #11 0x00000000004778c4 main (/usr/bin/swift+0x4778c4) #12 0x00007f662cc9a830 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x20830) #13 0x0000000000475179 _start (/usr/bin/swift+0x475179) Stack dump: 0. P
fatalError()
Fatal error: file <stdin>, line 1 Current stack trace: 0 libswiftCore.so 0x00007f18b22e0680 _swift_stdlib_reportFatalErrorInFile + 221 1 libswiftCore.so 0x00007f18b204f38c <unavailable> + 1368972 2 libswiftCore.so 0x00007f18b22892f2 <unavailable> + 3703538 3 libswiftCore.so 0x00007f18b228a759 <unavailable> + 3708761 4 libswiftCore.so 0x00007f18b204ea86 <unavailable> + 1366662 5 libswiftCore.so 0x00007f18b22890bb <unavailable> + 3702971 6 libswiftCore.so 0x00007f18b204ea86 <unavailable> + 1366662 7 libswiftCore.so 0x00007f18b21bc0b9 <unavailable> + 2863289 8 libswiftCore.so 0x00007f18b204e3f0 _assertionFailure(_:_:file:line:flags:) + 44 10 swift 0x0000000000fed3be <unavailable> + 12506046 11 swift 0x0000000000ff1882 <unavailable> + 12523650 12 swift 0x00000000004d9076 <unavailable> + 888950 13 swift 0x00000000004c35d3 <unavailable> + 800211 14 swift 0x00000000004beecc <unavailable> + 782028 15 swift 0x00000000004778c4 <unavailable> + 489668 16 libc.so.6 0x00007f18b4ffc740 __libc_start_main + 240 17 swift 0x0000000000475179 <unavailable> + 479609 #0 0x0000000003f25074 PrintStackTraceSignalHandler(void*) (/usr/bin/swift+0x3f25074) #1 0x0000000003f253b6 SignalHandler(int) (/usr/bin/swift+0x3f253b6) #2 0x00007f18b68d2390 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x11390) #3 0x00007f18b21bc0b9 _T0s17_assertionFailures5NeverOs12StaticStringV_SSAE4fileSu4lines6UInt32V5flagstFTf4nxnnn_n (/usr/lib/swift/linux/libswiftCore.so+0x2bb0b9) #4 0x00007f18b204e41c _T0s17_assertionFailures5NeverOs12StaticStr
-assert-config Release
でprintCurrentBacktrace()
は呼ばれなくなる。@usableFromInline @_transparent internal func _fatalErrorFlags() -> UInt32 { // The current flags are: // (1 << 0): Report backtrace on fatal error #if os(iOS) || os(tvOS) || os(watchOS) return 0 #else return _isDebugAssertConfiguration() ? 1 : 0 #endif }
(edited)(lldb) attach 572 error: attach failed: Failed to connect port
// Linux root@031ab2443e1a:/var/vapor# lldb-server v lldb version 5.0.0 (git@github.com:apple/swift-lldb.git revision 76dfa56ed35eaa392f7e51088c08f08f1150d142) Swift-4.1 (revision f01501c324876fc07820dc28923d7088fb7af847) clang revision cd84be6c4294f9ec302c20c63a601cbaeaa6a017 llvm revision cf364153438b3ac07a4a7d721159936e439ba2e7
(edited)[omochi@omochi-iMac-PC43 ~]$ lldb --version lldb-360.0.0 (buildbot 2018-03-29) Swift-4.1 (revision f01501c324876fc07820dc28923d7088fb7af847) clang revision cd84be6c4294f9ec302c20c63a601cbaeaa6a017 llvm revision cf364153438b3ac07a4a7d721159936e439ba2e7
lldb-server
試した。docker-compose.yml
にprivileged: true
を追加。lldb-server
起動オプションに--min-gdbserver-port 31167 --max-gdbserver-port 31266
を追加。docker-compose.yml
のports
に- "31166-31266:31166-31266"
を追加。docker exec -it vapor lldb-server platform --listen "*:31166" --server --min-gdbserver-port 31167 --max-gdbserver-port 31266
でlldb-server
を起動。$ xcrun lldb (lldb) platform select remote-linux Platform: remote-linux Connected: no (lldb) platform connect connect://172.16.241.138:31166 Platform: remote-linux Triple: x86_64-*-linux-gnu OS Version: 4.9.93 (4.9.93-boot2docker) Kernel: #1 SMP Thu Jul 19 18:29:50 UTC 2018 Hostname: 88958a83a317 Connected: yes WorkingDir: /var/vapor (lldb) platform process list 4 matching processes were found on "remote-linux" PID PARENT USER TRIPLE NAME ====== ====== ========== ======================== ============================ 1 0 (null) x86_64-*-linux dash 338 1 x86_64-*-linux vapor 563 338 x86_64-*-linux Run 568 0 x86_64-*-linux lldb-server (lldb) platform process attach --pid 563 Process 563 stopped * thread #1, name = 'Run', stop reason = signal SIGSTOP frame #0: 0x00007f8f41cfe360 libpthread.so.0`__pthread_cond_wait + 192 libpthread.so.0`__pthread_cond_wait: -> 0x7f8f41cfe360 <+192>: movl (%rsp), %edi 0x7f8f41cfe363 <+195>: callq 0x7f8f41d011c0 ; __pthread_disable_asynccancel 0x7f8f41cfe368 <+200>: movq 0x8(%rsp), %rdi 0x7f8f41cfe36d <+205>: movl $0x1, %esi thread #2, name = 'Run', stop reason = signal SIGSTOP frame #0: 0x00007f8f41d00827 libpthread.so.0`do_futex_wait.constprop.3 + 55 …
(edited)docker-machine
を使ってるので、macOSのlldb
からの接続先が127.0.0.1ではないのが違うくらいかな。--min-gdbserver-port
を指定してるコマンドラインは見かけていたのですが、それについて調べても情報が出てこなかったのでスルーしていました。gdbの互換モードみたいな特殊な使い方があるのかな?みたいな。swift build --build-tests
すると、Xcode 12.01.1版は2分14秒、swift-5.3 OSS ToolchainのmacOS版は8分43秒かかった。 (edited)$ du -m $(DEVELOPER_DIR=/Applications/Xcode_11.7.app xcrun --find swift) $(xcrun --toolchain org.swift.525202008051a --find swift) $(xcrun --find swift) $(xcrun --toolchain org.swift.530202009161a --find swift) 39 /Applications/Xcode_11.7.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift 162 /Library/Developer/Toolchains/swift-5.2.5-RELEASE.xctoolchain/usr/bin/swift 97 /Applications/Xcode_12.0.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift 179 /Library/Developer/Toolchains/swift-5.3-RELEASE.xctoolchain/usr/bin/swift
(edited)--preset="buildbot_osx_package"
だからアサーションついてるぽい。 https://ci.swift.org/view/Swift%205.3/job/oss-swift-5.3-package-osx/
[preset: buildbot_osx_package] mixin-preset= mixin_osx_package_base mixin_osx_package_test mixin_lightweight_assertions,no-stdlib-asserts … # A mixin that enables 'lightweight' assertions that don't slow down the # compiler significantly. [preset: mixin_lightweight_assertions] assertions
https://github.com/apple/swift/blob/main/utils/build-presets.ini#L1306-L1310mixin_lightweight_assertions
が使われてる。 (edited)mixin_lightweight_assertions
のコメント、4倍遅いのはsignificantlyではないということなのか… Uncaught TypeError: Cannot read property 'getChildren' of undefined
JSがTypeErrorになったのでLeafがなんかおかしいのかな、、と思ったのですが、、、document.querySelector("#some-id")
とかがあるなら、この#に\を付ける必要があります。$('#loading')
のがいっぱいあるんですけど、それにエスケープをしていく必要があるんですね。。。#FAFAFA
はそのままでOKですか?<li class="nav-item" style="width: 140px;"> <a href="#tab1" class="nav-link py-1 active" data-toggle="tab"> <h6 style="font-size: large;"><i class="far fa-folder-tree"></i> Structure</h6> </a> </li> <li class="nav-item" style="width: 140px;"> <a href="#tab2" class="nav-link py-1" data-toggle="tab"> <h6 style="font-size: large;"><i class="fal fa-file-code"></i> Syntax</h6> </a> </li>
^ Bootstrapでこういうタブを作る指定があるんですけどこれもダメでしたね。"""
文字列で書いたほうが楽そう。\( )
で変数埋め込みすればほぼ衝突しないだろうし、#
を\#
に変える必要がある。 (edited)#
を\#
だからまだマシ (edited)app.get(/^\/([a-f0-9]{32})$/i, async (req, res) => {
^ Node.jsでいうこういうのを書きたいのですが、ちょっと調べた限り無理そう。class
が className
とかapp.get("*") { req -> EventLoopFuture<EventLoopFuture<View>> in let pattern = try! NSRegularExpression(pattern: #"^\/([a-f0-9]{32})$"#, options: [.caseInsensitive]) let matches = pattern.matches(in: req.url.path, options: [], range: NSRange(location: 0, length: NSString(string: req.url.path).length)) guard matches.count == 1 && matches[0].numberOfRanges == 2 else { throw Abort(.notFound) } let gistId = NSString(string: req.url.path).substring(with: matches[0].range(at: 1)) let promise = req.eventLoop.makePromise(of: EventLoopFuture<View>.self) let session = URLSession(configuration: .default) let request = URLRequest(url: URL(string: "https://api.github.com/gists/\(gistId)")!) session.dataTask(with: request) { (data, response, error) in if let error = error { promise.fail(error) return } guard let data = data else { promise.fail(Abort(.notFound)) return } guard let contents = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], let files = contents["files"] as? [String: Any], let filename = files.keys.first, let file = files[filename] as? [String: Any], let content = file["content"] as? String else { promise.fail(Abort(.notFound)) return } promise.succeed( req.view.render( "index", [ "title": "Swift AST Explorer", "defaultSampleCode": content, "swiftVersion": swiftVersion, ] ) ) } .resume() return promise.futureResult }
VaporでAsyncでビューを返すのってこれであってます?動いてるんですけど EventLoopFuture<EventLoopFuture<View>>
となってるところがホントに合ってるのかな?と。EventLoopFuture<View>
じゃないですかね?コンパイル通りますか?// ここをこうして let promise = req.eventLoop.makePromise(of: View.self) // ここをこう req.view.render( "index", [ "title": "Swift AST Explorer", "defaultSampleCode": content, "swiftVersion": swiftVersion, ] ).cascase(to: promise)
(edited).cascase(to: promise)
っていうのがあるんですね!request.client
がありますよ。/build/Sources/App/routes.swift:31:23: error: 'URLSession' is unavailable: This type has moved to the FoundationNetworking module. Import that module to use it. let session = URLSession(configuration: .default) ^~~~~~~~~~ Foundation.URLSession:2:18: note: 'URLSession' has been explicitly marked unavailable here public typealias URLSession = AnyObject
確かにFoundationNetworkingに移ったって書いてありましたわ。 return Response( status: .ok, headers: ["Content-Type": "text/html; charset=UTF-8"], body: Response.Body(string: html) )
View
型だとどうなってるんだろうな。public struct View: ResponseEncodable { public var data: ByteBuffer public init(data: ByteBuffer) { self.data = data } public func encodeResponse(for request: Request) -> EventLoopFuture<Response> { let response = Response() response.headers.contentType = .html response.body = .init(buffer: self.data) return request.eventLoop.makeSucceededFuture(response) } }
return view.encodeResponse(for: request).map { (response) in var response = response response.status = .notFound return response }
@discardableResult public func get<Response>( _ path: PathComponent..., use closure: @escaping (Request) throws -> Response ) -> Route where Response: ResponseEncodable { return self.on(.GET, path, use: closure) }
Response
は型パラメータ名だけど、 同じ名前の Response
型 もある )struct CSRFProtection { struct Key: StorageKey { typealias Value = CSRFProtection } struct Post: Decodable { var csrfToken: UUID? } let sessionKey = "csrfToken" struct Middleware: Vapor.Middleware { func respond(to request: Request, chainingTo next: Responder) -> EventLoopFuture<Response> { let eventLoop = request.eventLoop guard request.method == .POST else { return next.respond(to: request) } let verify = eventLoop.future { try request.verifyCSRFToken() } return verify.flatMap { () in next.respond(to: request) } } } var middleware: Middleware { Middleware() } }
respond (to:, chainingTo)
メソッドを実装するだけなので。next.respond(to: request).flatMapError{ (error) in ... switch error { // errorの型をがんばって404と500を振り分ける case ... }
(edited)http://localhost:8080/b4f866efb1c1dc63b0a9cce000cf5688
こういうPathを受けるために /*
で受けてると難しい気がするな。struct RouteNotFound: Error { } extension RouteNotFound: AbortError { static var typeIdentifier: String { "Abort" } var status: HTTPResponseStatus { .notFound } }
final class ErrorMiddleware: Middleware { func respond(to request: Request, chainingTo next: Responder) -> EventLoopFuture<Response> { return next.respond(to: request).flatMapError { (error) in let headers: HTTPHeaders let status: HTTPResponseStatus let reason: String let title: String switch error { case let abort as AbortError: headers = abort.headers status = abort.status title = "Not Found" reason = status == .notFound ? "Sorry, an error has occured, Requested page not found!" : abort.reason default: headers = [:] status = .internalServerError title = "Internal Server Error" reason = "Something went wrong." } return request.view.render("error", [ "title": title, "status": "\(status.code)", "reason": reason, ]) .encodeResponse(status: status, headers: headers, for: request) } } }
ミドルウェアはとりあえずこんな感じにしました。error.leaf
っていうテンプレートがあって、タイトルとかが変わります。<html><body>hello world</body></html>
static var updateDatePropertyKeyPath: KeyPath<PasswordResetModel, TimestampProperty<PasswordResetModel, DefaultTimestampFormat>> { \.$updateDate }
app.post("update") { req -> EventLoopFuture<SyntaxResponse> in
を app.on(.POST, "update", body: .collect(maxSize: "10mb")) { req -> EventLoopFuture<SyntaxResponse> in
でいいのかな。 そうするとルーティングは全部 app.on(.POST
形式に合わせた方が見やすいかな。public final class Routes: RoutesBuilder, CustomStringConvertible { public var all: [Route] /// Default value used by `HTTPBodyStreamStrategy.collect` when `maxSize` is `nil`. public var defaultMaxBodySize: ByteCount /// Default routing behavior of `DefaultResponder` is case-sensitive; configure to `true` prior to /// Application start handle `Constant` `PathComponents` in a case-insensitive manner. public var caseInsensitive: Bool public var description: String { return self.all.description } public init() { self.all = [] self.defaultMaxBodySize = "16kb" self.caseInsensitive = false } public func add(_ route: Route) { self.all.append(route) } } extension Application: RoutesBuilder { public func add(_ route: Route) { self.routes.add(route) } }
on(.POST, "update", body: .collect(maxSize: "10mb"))
の一択っぽい.stream
にして、リクエストハンドラでチマチマ読み出すことはできます#
にエスケープがいる仕様はリファクタリングの過程で別のファイル(〜.cssや〜.js)に分けると今度は戻さないといけないんだけど、忘れると静かに表示が壊れる。@resultBuilder
を使った HTML のテンプレートエンジン的なものがあれば使いやすかったりするでしょうか?目的が違うから微妙?でも API が似てたら両方を触りやすい気も。 (edited)div(id: "foos") { for foo in foos { img(src: "img/\(foo.id).png", alt: "foo") } }
tag("img", ["src": "img/foo.png", "alt": "foo"])
みたいに逃げられる。 (edited)@resultBuilder
で書けたらうれしいこともありそうな?@resultBuilder
でいい気もします。@resultBuilder
だと思うんですけどねぇ・・・。#for(version in versions): <option value="#(version)">#(version)</option> #endfor
こう書くみたいだな。 ドキュメント(1つ前のバージョンしかない)に載ってるのは <ul> #for(planet in planets) { <li>#(planet)</li> } </ul>
#if(version == stableVersion): <option value="#(version)" selected>#(version)</option> #else: <option value="#(version)">#(version)</option> #endif
Ifもこんな感じっぽい。 https://forums.swift.org/t/pitch-new-leaf-body-syntax/18188#
を使うのをやめてほしいと思っているが。。。[]
もJSで使うから厳しそう…"\\\\\\\\"
になりそう{{}}
もだめかも。!
が使えるくらいですね。 あとはカスタムタグで頑張るしかない。カスタムタグ使ったことないですが"Hello #custom(name)"
うーむ。思ってたのと違うなあ。 app.get("*") { req -> EventLoopFuture<View> in guard let pattern = try? NSRegularExpression(pattern: #"^\/([a-f0-9]{32})$"#, options: [.caseInsensitive]) else { throw Abort(.internalServerError) }
^ みたいな正規表現を使ったルーティング、増えてくると大変だから1つ1つ書きたい。swift build
したらどの辺りにエラーが出てくるでしょうね。FIR
プレフィックス付きのが見え隠れしてました。async/await
が来て、 Python の async/await
と連携して、さらに Firebase SDK for Python が async/await
に対応してて、違いがうまく吸収されるようになるという夢のような状況なら連携しやすそうですが、なかなか難しそうですね・・・。Promise
に包むのと剥がすのだけでうまくいく?async
は JS の世界に閉じてるから、単に Promise
を返す関数というだけだから、 JS で Promise
を返す関数を await
したときに、うまく剥がしてやれば良い?async
になっちゃうのか。throws
はどうなってるんですっけ?let divElement = document.createElement!("div").object!
この createElement
とか try
なしで呼べているのはなぜ??async
であることをアノテートする、になりますね。let divElement = document.createElement!.throwing("div").object!
let result = fetch!.async("...")
throwing
も throws
の方が対応がわかりやすそうだけど(英語としてどうかは別として)。throwing
フィールドがあるかも知れないんですよねthrowing
は JSValue
のメソッドではなく、 JS 側で持ってるってことですか?throwing
が出てこないですが、どこに実装あるんでしょうか?JSValue
を受ける関数にするのはどうでしょうか? let foo = try jsTry(jsFoo)
JSValue
の中に throw
されたエラーの情報を閉じ込めておいて。 (edited)func suspendAsync<T>(
^ こういう文字列をLeafで置換すると func suspendAsync(
みたいに <T>
が消えるんだけどどういうことなの<T>
こういう形になってない <
や >
はOKだし何のためにやってるのかわからない。#raw()
ってのが使えたらしいけどすでになく、カスタムタグを作るという方法があるらしいけど、よくわからなかった。カスタムタグを通しても消える。t2.micro
インスタンスではメモリ不足でクラッシュしてしまったt2.small
にしたらビルドできた。$ top
で見てたら swiftプロセスが 900M ぐらいもっていく瞬間があるのは見えたfunc suspendAsync<T>(
の埋め込み こちらではソースには<T>
出てました。@Parent
リレーションは、 self.$parent.id
が non optional で self.parent.id
が optional なのはうまいことできてて良いな。self.parent.id
も non optional になっててほしいけどParentModel.id
そのものが optional なのは レコードの新規作成を考えると正しい。RUN groupadd docker -g ${HOST_DOCKER_GROUP_ID} && \ usermod -a -G docker vapor
HOST_DOCKER_GROUP_ID
はビルドするマシンは別だから一回SSHにログインして取る。TERM=xterm ssh -t -t -o 'StrictHostKeyChecking no' "${{ secrets.SSH_LOGIN_USER }}@${{ secrets.SSH_HOST }}" "grep "^docker:" /etc/group | sed -e 's/^[^:]\+:[^:]\+:\([^:]\+\):[^:]\+$/\1/g'" > gid REMOTE_DOCKER_GID=$(echo $(tail -n 1 gid) | sed -e 's/\r//g')
CIの最初の方でこんな感じでとってる。 デプロイ先は getent
も入ってないOSだからグループIDを取るだけなのに結構ややこしいことをしている。 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro
で、それ以外のDockerのCLIとかはコンテナに別途インストールするんですけど、docker.sockがrootかdockerグループにいないと読めないんですけど、rootかホストと同じGIDのdockerグループ、でしたね。私の環境では。services: app: image: kishikawakatsumi/swift-playground:latest container_name: swift-playground depends_on: - letsencrypt env_file: - .env environment: HOST_PWD: $PWD/
このボリュームを孫にマウントできるようにするのをポータブルにするためにdocker-compose.ymlでホストのカレントディレクトリ を渡しています。こういう書き方ができるのがよかった。let tanner = User(name: "Tanner", age: 23, pets: ["Zizek", "Foo"], dict: ["a": 1, "b": 2], foos: [.baz], nums: [3.14], isCool: true) let ravneet = User(name: "Ravneet", age: 33, pets: ["Piku"], dict: ["a": -3, "b": 99], foos: [.baz, .bar], nums: [3.14, 144], isCool: true) let usersToEncode = Users(users: [tanner, ravneet]) let result = try URLEncodedFormEncoder().encode(usersToEncode) XCTAssert(result.contains("users[0][pets][]=Zizek")) XCTAssert(result.contains("users[0][pets][]=Foo")) XCTAssert(result.contains("users[0][age]=23")) XCTAssert(result.contains("users[0][name]=Tanner")) XCTAssert(result.contains("users[0][dict][a]=1")) XCTAssert(result.contains("users[0][dict][b]=2")) XCTAssert(result.contains("users[0][foos][]=baz")) XCTAssert(result.contains("users[0][nums][]=3.14")) XCTAssert(result.contains("users[0][isCool]=true"))
[ ]
を使ってパスを表すスタイル自体はPHPからあるんですが・・・x-www-form-urlencoded
で規格になってるけど。[
をパーセントエスケープするところがちょっと違うな。<xmp>...</xmp>
で囲うことで<T>みたいなタグっぽい部分の出るようになりました。 ということでLeafは濡れ衣でしたpublic protocol Middleware { func respond(to request: Request, chainingTo next: Responder) -> EventLoopFuture<Response> } public protocol Responder { func respond(to request: Request) -> EventLoopFuture<Response> }
(edited) func add(_ collection: RouteCollection, csrf: Bool = true, login: Bool = true) throws { var middlewares: [Middleware] = [] if csrf { middlewares.append(csrfProtection.middleware) } if login { middlewares += userLoginGuard(doesRedirect: true) } try routes.group(middlewares) { (routes) in try routes.register(collection: collection) } }
DocumentSymbolRequest.Response
は Codable
なんですけど Conditional conformance of type 'Optional<Wrapped>' to protocol 'Content' does not imply conformance to inherited protocol 'RequestDecodable'
というエラーで、 定義は public struct DocumentSymbolRequest: TextDocumentRequest, Hashable { public static let method: String = "textDocument/documentSymbol" public typealias Response = DocumentSymbolResponse? /// The document in which to lookup the symbol location. public var textDocument: TextDocumentIdentifier public init(textDocument: TextDocumentIdentifier) { self.textDocument = textDocument } }
なので typealias Response = DocumentSymbolResponse?
のところが問題なのかな? ちなみに、 DocumentSymbolResponse
の方は extension DocumentSymbolResponse: Content {}
でOK。 (edited)extension DocumentSymbolRequest.Response: ResponseEncodable {} extension DocumentSymbolRequest.Response: RequestDecodable {} extension DocumentSymbolRequest.Response: Content {}
上の二行を追加するとコンパイルできます。コンパイラのバグっぽい? (edited)protocol Content: Codable, RequestDecodable, ResponseEncodable
ContentっていうのはそもそもCodable + RequestDecodable + ResponseEncodable なんですね。extension DocumentSymbolRequest.Response: Content, RequestDecodable, ResponseEncodable {}
はコンパイルできるけど、 extension DocumentSymbolRequest.Response: RequestDecodable, ResponseEncodable {}
は同じエラーでダメ。does not imply conformance to inherited protocol 'RequestDecodable'
なのでRequestDecodableを書く必要があるって言ってる気がするんですが、一般には Content
だけで済むはずですよね。public protocol ResponseEncodable { func encodeResponse() } public protocol Content: Codable, ResponseEncodable { } extension Content { func encodeResponse() {} } struct MyType: Codable {} extension Optional: Content where Wrapped == MyType {}
<stdin>:13:1: error: conditional conformance of type 'Optional<Wrapped>' to protocol 'Content' does not imply conformance to inherited protocol 'ResponseEncodable' extension Optional: Content where Wrapped == MyType {} ^ <stdin>:13:1: note: did you mean to explicitly state the conformance like 'extension Optional: ResponseEncodable where ...'? extension Optional: Content where Wrapped == MyType {} ^ <stdin>:13:1: error: method 'encodeResponse()' must be declared public because it matches a requirement in public protocol 'ResponseEncodable' extension Optional: Content where Wrapped == MyType {} ^ <stdin>:9:10: note: mark the instance method as 'public' to satisfy the requirement func encodeResponse() {} ^ public
protocol ResponseEncodable {} protocol Content: ResponseEncodable {} //extension Optional: Content {} // OK extension Optional: Content where Wrapped == String {} // NG
(edited)<stdin>:4:1: error: conditional conformance of type 'Optional<Wrapped>' to protocol 'Content' does not imply conformance to inherited protocol 'ResponseEncodable' extension Optional: Content where Wrapped == String {} // NG ^ <stdin>:4:1: note: did you mean to explicitly state the conformance like 'extension Optional: ResponseEncodable where ...'? extension Optional: Content where Wrapped == String {} // NG ^
(edited)Codable
も関係無さそうです。 protocolの親子関係とextensionのwhere句が条件と思われます。app.on(.POST, "shared_link", body: .collect(maxSize: "10mb")) { (req) -> EventLoopFuture<[String: String]> in
VaporはPOSTボディのデフォルトのサイズ制限が意外と小さいっていうのに当たった。app.on(.POST, "shared_link", body: .collect(maxSize: "10mb"))
を現在はすべて指定していくのが正しい、であってます?application.routes.defaultMaxBodySize