Slide 1

Slide 1 text

torͰ͓͏ͪAPI
 ɹΛϦϓϨʔεͨ͠࿩ 2017/12/18 CA.kt #5 @େࡕ Itsuki AOYAGI

Slide 2

Slide 2 text

͍͋ͭ͝͞ - ࣗݾ঺հ - • ໊લ : ੨༄ थ Itsuki AOYAGIʢ23ʣ
 a.k.a ΍͗ʹ͍ • AndroidΞϓϦΤϯδχΞ • Kotlinྺ : ໿൒೥ • Twitter : @yaginier • GitHub etc… : @yagi2 / @yagi21 • ͓͏͍͖ͪͩ͢

Slide 3

Slide 3 text

͍͋ͭ͝͞ - ࣗݾ঺հ - • ໊લ : ੨༄ थ Itsuki AOYAGIʢ23ʣ
 a.k.a ΍͗ʹ͍ • AndroidΞϓϦΤϯδχΞ • Kotlinྺ : ໿൒೥ • Twitter : @yaginier • GitHub etc… : @yagi2 / @yagi21 • ͓͏͍͖ͪͩ͢

Slide 4

Slide 4 text

͓͏ͪϋοΫͯ͠·͔͢ʁ

Slide 5

Slide 5 text

͓͏ͪϋοΫ ͓͏ͪΛΑΓշదͳ΋ͷʹ͢ΔͨΊʹ ΨδΣοτ΍αʔϏεΛ૊Έ߹Θͤͯ ϋοϐʔʹ͢ΔͨΊͷ͋Ε͜Ε ɻ ࠷ۙͩͱεϚʔτεϐʔΧʔ͕͍ͬͺ͍͋ΔͷͰ ͦΕΒܦ༝ͰՈిͱ͔Λૢ࡞Ͱ͖Δɻ

Slide 6

Slide 6 text

͓͏ͪϋοΫ - զ͕Ո - ɾRaspberry Piʢॳ୅ʣ ɹˠ ͓͏ͪAPI͕͸͍͑ͯΔʢPHPʣ ɹɹˠ ϒϥ΢β͔ΒHTTPSܦ༝ͯ͠ϖʔδ͔Βୟ͘ ɹɹˠ ࣗ࡞ͷAndroidΞϓϦ͔ΒϦΫΤετ Ұྫ ɾࣗ୐ͷσεΫτοϓPCͷిݯΛ֎͔ΒೖΕΔ ɾΤΞίϯɺςϨϏ౳ͷ੺֎ઢͰૢ࡞͢ΔՈిͷૢ࡞ ɾϥδΦʢRasPiΛrtmpετϦʔϛϯά࢖ͬͯϥδΦʹ͍ͯͨ͠ʣ

Slide 7

Slide 7 text

͓͏ͪϋοΫ - զ͕Ո - ɾRaspberry Piʢॳ୅ʣ ɹˠ ͓͏ͪAPI͕͸͍͑ͯΔʢPHPʣ ɹɹˠ ϒϥ΢β͔ΒHTTPSܦ༝ͯ͠ϖʔδ͔Βୟ͘ ɹɹˠ ࣗ࡞ͷAndroidΞϓϦ͔ΒϦΫΤετ Ұྫ ɾࣗ୐ͷσεΫτοϓPCͷిݯΛ֎͔ΒೖΕΔ ɾΤΞίϯɺςϨϏ౳ͷ੺֎ઢͰૢ࡞͢ΔՈిͷૢ࡞ ɾϥδΦʢRasPiΛrtmpετϦʔϛϯά࢖ͬͯϥδΦʹ͍ͯͨ͠ʣ

Slide 8

Slide 8 text

͓͏ͪϋοΫ - զ͕Ո - ɾRaspberry Piʢॳ୅ʣ ɹˠ ͓͏ͪAPI͕͸͍͑ͯΔʢPHPʣ ɹɹˠ ϒϥ΢β͔ΒHTTPSܦ༝ͯ͠ϖʔδ͔Βୟ͘ ɹɹˠ ࣗ࡞ͷAndroidΞϓϦ͔ΒϦΫΤετ Ұྫ ɾࣗ୐ͷσεΫτοϓPCͷిݯΛ֎͔ΒೖΕΔ ɾΤΞίϯɺςϨϏ౳ͷ੺֎ઢͰૢ࡞͢ΔՈిͷૢ࡞ ɾϥδΦʢRasPiΛrtmpετϦʔϛϯά࢖ͬͯϥδΦʹ͍ͯͨ͠ʣ ͍ͭ͜ΛKotlinʹॻ͖׵͑Δ

Slide 9

Slide 9 text

αʔόʔαΠυ Kotlin

Slide 10

Slide 10 text

αʔόʔαΠυKotlin ɾSpring Boot ɹҎલKotlin + Spring BootͰJSONΛు͘APIΛ࡞ͬͨ͜ͱ͕͋Δ ɹ ͦͷ࣌ͷϒϩά → KotlinͱSpring BootΛ࢖ͬͯαΫοͱୟ͚ΔAPIΛ࡞Δ ɾKotr ɹΊͬͪΌബ͍ ɹ ɹKtor is a framework for quickly creating web applications in Kotlin with minimal effort.

Slide 11

Slide 11 text

Ktor fun main(args: Array) { embeddedServer(Netty, 8080) { routing { get("/") { call.respondText("Hello, world!", ContentType.Text.Html) } } }.start(wait = true) } ɾബ͗ͯ͢README͕୹͍ ɹɹɹɹউखͳΠϝʔδ ɹɹɹɹɹɹɹSpringBoot → Ruby on Rails ɹɹɹɹɹɹɹKtor → Sinatra

Slide 12

Slide 12 text

Ktor - WoL API - KtorΛ࢖ͬͯɺࣗ୐PCͷిݯΛ֎͔ΒೖΕΔAPIΛॻ͖௚͢ ݱࡏͷ࢓༷ ɾΫϥΠΞϯτ͸POSTͰର৅ͷMacΞυϨεΛ౤͛Δ ɾαʔόʔ͸ड͚औͬͨΒͦͷMacΞυϨεʹରͯ͠WoL͢Δ ɹʢexecͰwakeonlanίϚϯυΛୟ͍͍ͯΔʣ

Slide 13

Slide 13 text

Ktor - WoL API - KtorΛ࢖ͬͯɺࣗ୐PCͷిݯΛ֎͔ΒೖΕΔAPIΛॻ͖௚͢ ৽͍͠࢓༷ ɾΫϥΠΞϯτ͸POSTͰର৅ͷϗετ໊Λ౤͛Δ ɹˠ ϗετ໊΍ͦΕʹ४ͣΔ΋ͷʢཧ༝͸ޙड़ʣΛ౤͛Δ ɹˠ DB౳αʔόʔଆͰϗετ໊ͱMacΞυϨεΛ͓͍࣋ͬͯͯࢀর ɾαʔόʔ͸ड͚औͬͨΒର৅ʹରͯ͠WoL͢Δ ɹ͔ͤͬ͘ͳͷͰϚδοΫύέοτૹ৴Λ࣮૷͢Δ

Slide 14

Slide 14 text

Ktor - WoL API - install(Routing) { post("/wol") { val name = call.receiveParameters()[“name”] val host = ϗετΛDB͔Βݕࡧ(name) if (host == null) { call.respond("ݟ͔ͭΒͳ͔ͬͨ") } else { try { WakeOnLan(host.macAddr).sendMagicPacket() call.respond("ૹͬͨ") } catch (e: IOException) { call.respond("ૹΔͷʹࣦഊͨ͠") } } } ɾPOSTͰड͚औͬͯϚδοΫύέοτΛૹΔ ɹˠ Ͳͷϗετʹରͯ͠ϚδοΫύέοτΛૹΔͷ͔͸ύϥϝʔλͰ ɹˠ DBʹ͸Exposed + MySQLΛ࢖༻

Slide 15

Slide 15 text

Ktor - WoL API - install(Routing) { post("/wol") { val name = call.receiveParameters()[“name”] val host = ϗετΛDB͔Βݕࡧ(name) if (host == null) { call.respond("ݟ͔ͭΒͳ͔ͬͨ") } else { try { WakeOnLan(host.macAddr).sendMagicPacket() call.respond("ૹͬͨ") } catch (e: IOException) { call.respond("ૹΔͷʹࣦഊͨ͠") } } } ɾPOSTͰड͚औͬͯϚδοΫύέοτΛૹΔ ɹˠ Ͳͷϗετʹରͯ͠ϚδοΫύέοτΛૹΔͷ͔͸ύϥϝʔλͰ ɹˠ DBʹ͸Exposed + MySQLΛ࢖༻

Slide 16

Slide 16 text

Ktor - WoL API - install(Routing) { post("/wol") { val name = call.receiveParameters()[“name”] val host = ϗετΛDB͔Βݕࡧ(name) if (host == null) { call.respond("ݟ͔ͭΒͳ͔ͬͨ") } else { try { WakeOnLan(host.macAddr).sendMagicPacket() call.respond("ૹͬͨ") } catch (e: IOException) { call.respond("ૹΔͷʹࣦഊͨ͠") } } } ɾPOSTͰड͚औͬͯϚδοΫύέοτΛૹΔ ɹˠ Ͳͷϗετʹରͯ͠ϚδοΫύέοτΛૹΔͷ͔͸ύϥϝʔλͰ ɹˠ DBʹ͸Exposed + MySQLΛ࢖༻ object Computers : IntIdTable() { val hostName = varchar("hostname", 50).index() val macAddr = varchar("mac_addr", 50) } class Computer(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(Computers) var hostname by Computers.hostName var macAddr by Computers.macAddr } fun findByHostName(hostName: String?): Computer? { return transaction { Computer.find { Computers.hostName eq hostName }.firstOrNull() } }

Slide 17

Slide 17 text

Ktor - WoL API - install(Routing) { post("/wol") { val name = call.receiveParameters()[“name”] val host = ϗετΛDB͔Βݕࡧ(name) if (host == null) { call.respond("ݟ͔ͭΒͳ͔ͬͨ") } else { try { WakeOnLan(host.macAddr).sendMagicPacket() call.respond("ૹͬͨ") } catch (e: IOException) { call.respond("ૹΔͷʹࣦഊͨ͠") } } } ɾPOSTͰड͚औͬͯϚδοΫύέοτΛૹΔ ɹˠ Ͳͷϗετʹରͯ͠ϚδοΫύέοτΛૹΔͷ͔͸ύϥϝʔλͰ ɹˠ DBʹ͸Exposed + MySQLΛ࢖༻

Slide 18

Slide 18 text

Ktor - WoL API - class WakeOnLan(private val macAddress: String) { @Throws(IOException::class) fun sendMagicPacket() { val iNetAddress = InetAddress.getByName("255.255.255.255") val magicPacket = getMagicPacket(macAddress) DatagramSocket().send(DatagramPacket(magicPacket, magicPacket.size, iNetAddress, 8080)) } private fun getMagicPacket(macAddress: String): ByteArray { val packet = ByteArray(102) var index = 0 repeat(6) { packet[index++] = 0xFF.toByte() } val macAddressByte = getMacAddressByte(macAddress) repeat(16) { repeat(6) { packet[index++] = macAddressByte[it] } } return packet } private fun getMacAddressByte(macAddress: String): ByteArray = macAddress.split(":").map { Integer.parseInt(it, 16).toByte() }.toByteArray() }

Slide 19

Slide 19 text

׬੒ʂ ͨ͠ͷͰɺGoogleHome͔Β࢖͑ΔΑ͏ʹ͢Δ

Slide 20

Slide 20 text

Google Home + IFTTT Google HomeͷԻ੠ίϚϯυͰIFTTTͷτϦΨʔΛୟ͍ͯ IFTTT͸WebHookͰ͓ՈAPIʹPOST͢Δ

Slide 21

Slide 21 text

Google Home + IFTTT ໰୊఺ ී௨ʹϓϩάϥϜ͔ΒPOST͢Δͱ͖͸ $ curl --data-urlencode "name=hoge" http://api.example.com/wol Google Homeͩͱ”name=hoge”͕ͭΒ͍ ɹˠ ೔ຊޠͰͷΤΠϦΞεΛ෇͚ͯDBͷΧϥϜʹೖΕ͓ͯ͘ ྫʣʮͶ͐ɺGoogle ͏ͪͷ͜ͱΓΛىͯ͜͠ʯ ɹɹˠ name=͜ͱΓ ɹɹˠ DB͔Βʮ͜ͱΓʯͰҰக͢ΔͷΛݕࡧͯ͠΍Δ

Slide 22

Slide 22 text

Google Home + IFTTT object Computers : IntIdTable() { val hostName = varchar("hostname", 50).index() val macAddr = varchar("mac_addr", 50) } class Computer(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(Computers) var hostname by Computers.hostName var macAddr by Computers.macAddr } fun findByHostName(hostName: String?): Computer? { return transaction { Computer.find { Computers.hostName eq hostName }.firstOrNull() } } object Computers : IntIdTable() { val hostName = varchar("hostname", 50).index() val name = varchar("name", 50) val macAddr = varchar("mac_addr", 50) } class Computer(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(Computers) var hostname by Computers.hostName var name by Computers.name var macAddr by Computers.macAddr } fun findByHostName(hostName: String?): Computer? { return transaction { Computer.find { Computers.hostName eq hostName }.firstOrNull() } } fun findByName(name: String?): Computer? { return transaction { Computer.find { Computers.name eq name }.firstOrNull() } }

Slide 23

Slide 23 text

Google Home + IFTTT transaction { Computer.new { hostname = "kotori" name = "͜ͱΓ" macAddr = “FF:FF:FF:FF:FF:FF” } } ͓Ոʹ͋ΔϚγϯΛDBʹೖΕͯ͋͛Δɻ $ curl --data-urlencode "name=kotori" http://api.example.com:/wol ʮͶ͐ɺGoogle ͓͏ͪͷ͜ͱΓΛىͯ͜͠ʯ ✨྆ํڞOK✨


Slide 24

Slide 24 text

Google Home + IFTTT ஫ҙ఺ ʮͶ͐ɺGoogle ͏ͪͷ͜ͻͳͨΛىͯ͜͠ʯ → ౉ͬͯ͘Δ໊લ͕ʮ͜ ͻͳ ͨʯ ʮͶ͐ɺGoogle ͏ͪͷͪΌͪΌΛىͯ͜͠ʯ → ౉ͬͯ͘Δ໊લ͕ʮ஡ʑʯ ղܾࡦ → 1ճࢼͯ͠Կ͕౉ͬͯ͘Δͷ͔ΛݟΔ

Slide 25

Slide 25 text

ຊ೔ͷ͓͠ͳ͕͖ ɾAPI ɹˠ https://github.com/yagi2/Kaya ɾKtor ɹˠ https://github.com/ktorio/ktor ɾExposed ɹˠ https://github.com/JetBrains/Exposed

Slide 26

Slide 26 text

Have a Nice Kotlin!