temporary commit

This commit is contained in:
2022-03-17 19:45:58 +08:00
parent 4300b89db5
commit b75f7a7655
10 changed files with 358 additions and 17 deletions

View File

@@ -11,10 +11,17 @@ group = 'net.woggioni'
version = getProperty('gbcs.version') version = getProperty('gbcs.version')
repositories { repositories {
maven {
url = 'https://woggioni.net/mvn'
content {
includeModule 'net.woggioni', 'jwo'
}
}
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
implementation group: 'net.woggioni', name: 'jwo', version: getProperty('jwo.version')
implementation group: 'org.slf4j', name: 'slf4j-api', version: getProperty('slf4j.version') implementation group: 'org.slf4j', name: 'slf4j-api', version: getProperty('slf4j.version')
implementation group: 'io.netty', name: 'netty-codec-http', version: getProperty('netty.version') implementation group: 'io.netty', name: 'netty-codec-http', version: getProperty('netty.version')

View File

@@ -5,6 +5,7 @@ kotlin.version = 1.6.10
envelope.gradle.plugin.version = 1.0-SNAPSHOT envelope.gradle.plugin.version = 1.0-SNAPSHOT
lombok.gradle.plugin.version = 0.1 lombok.gradle.plugin.version = 0.1
jwo.version = 1.0-SNAPSHOT
junit.jupiter.version = 5.8.2 junit.jupiter.version = 5.8.2
netty.version = 4.1.74.Final netty.version = 4.1.74.Final
h2.version = 2.1.210 h2.version = 2.1.210

View File

@@ -1,4 +1,6 @@
module net.woggioni.gbcs { module net.woggioni.gbcs {
requires java.xml;
requires java.logging;
requires kotlin.stdlib; requires kotlin.stdlib;
requires io.netty.buffer; requires io.netty.buffer;
requires io.netty.transport; requires io.netty.transport;
@@ -6,7 +8,8 @@ module net.woggioni.gbcs {
requires io.netty.common; requires io.netty.common;
requires io.netty.handler; requires io.netty.handler;
requires io.netty.codec; requires io.netty.codec;
requires java.logging;
requires org.slf4j; requires org.slf4j;
requires net.woggioni.jwo;
exports net.woggioni.gbcs; exports net.woggioni.gbcs;
} }

View File

@@ -0,0 +1,10 @@
package net.woggioni.gbcs
import java.nio.file.Path
data class Configuration(
val cacheFolder : Path,
val host : String,
val port : Int,
val users : Map<String, Set<Role>>
)

View File

@@ -34,10 +34,12 @@ import io.netty.handler.stream.ChunkedNioFile
import io.netty.handler.stream.ChunkedWriteHandler import io.netty.handler.stream.ChunkedWriteHandler
import io.netty.util.concurrent.DefaultEventExecutorGroup import io.netty.util.concurrent.DefaultEventExecutorGroup
import io.netty.util.concurrent.EventExecutorGroup import io.netty.util.concurrent.EventExecutorGroup
import net.woggioni.jwo.JWO
import java.nio.channels.FileChannel import java.nio.channels.FileChannel
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import java.nio.file.StandardCopyOption
import java.nio.file.StandardOpenOption import java.nio.file.StandardOpenOption
import java.security.MessageDigest import java.security.MessageDigest
import java.util.AbstractMap.SimpleEntry import java.util.AbstractMap.SimpleEntry
@@ -208,8 +210,15 @@ class GradleBuildCacheServer {
} }
val content = msg.content() val content = msg.content()
val file = cacheDir.resolve(digestString(key.toByteArray())) val file = cacheDir.resolve(digestString(key.toByteArray()))
Files.newOutputStream(file).use { val tmpFile = Files.createTempFile(cacheDir, null, ".tmp")
content.readBytes(it, content.readableBytes()) try {
Files.newOutputStream(tmpFile).use {
content.readBytes(it, content.readableBytes())
}
Files.move(tmpFile, file, StandardCopyOption.ATOMIC_MOVE)
} catch (t : Throwable) {
Files.delete(tmpFile)
throw t
} }
val response = DefaultFullHttpResponse(msg.protocolVersion(), HttpResponseStatus.CREATED, val response = DefaultFullHttpResponse(msg.protocolVersion(), HttpResponseStatus.CREATED,
Unpooled.copiedBuffer(key.toByteArray())) Unpooled.copiedBuffer(key.toByteArray()))
@@ -268,18 +277,6 @@ class GradleBuildCacheServer {
GradleBuildCacheServer().run() GradleBuildCacheServer().run()
} }
private val hexArray = "0123456789ABCDEF".toCharArray()
fun bytesToHex(bytes: ByteArray): String {
val hexChars = CharArray(bytes.size * 2)
for (j in bytes.indices) {
val v: Int = bytes[j].toInt().and(0xFF)
hexChars[j * 2] = hexArray[v ushr 4]
hexChars[j * 2 + 1] = hexArray[v and 0x0F]
}
return String(hexChars)
}
fun digest(data : ByteArray, fun digest(data : ByteArray,
md : MessageDigest = MessageDigest.getInstance("MD5")) : ByteArray { md : MessageDigest = MessageDigest.getInstance("MD5")) : ByteArray {
md.update(data) md.update(data)
@@ -288,7 +285,7 @@ class GradleBuildCacheServer {
fun digestString(data : ByteArray, fun digestString(data : ByteArray,
md : MessageDigest = MessageDigest.getInstance("MD5")) : String { md : MessageDigest = MessageDigest.getInstance("MD5")) : String {
return bytesToHex(digest(data, md)) return JWO.bytesToHex(digest(data, md))
} }
} }
} }

View File

@@ -0,0 +1,5 @@
package net.woggioni.gbcs
enum class Role {
Reader, Writer
}

View File

@@ -0,0 +1,118 @@
package net.woggioni.gbcs
import org.slf4j.LoggerFactory
import org.w3c.dom.Document
import org.xml.sax.ErrorHandler
import org.xml.sax.SAXNotRecognizedException
import org.xml.sax.SAXNotSupportedException
import org.xml.sax.SAXParseException
import java.net.URL
import javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD
import javax.xml.XMLConstants.ACCESS_EXTERNAL_SCHEMA
import javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING
import javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI
import javax.xml.parsers.DocumentBuilder
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.validation.Schema
import javax.xml.validation.SchemaFactory
object Xml {
private class XmlErrorHandler(private val fileURL: URL) : ErrorHandler {
companion object {
private val log = LoggerFactory.getLogger(XmlErrorHandler::class.java)
}
override fun warning(ex: SAXParseException) {
log.warn(
"Problem at {}:{}:{} parsing deployment configuration: {}",
fileURL, ex.lineNumber, ex.columnNumber, ex.message
)
}
override fun error(ex: SAXParseException) {
log.error(
"Problem at {}:{}:{} parsing deployment configuration: {}",
fileURL, ex.lineNumber, ex.columnNumber, ex.message
)
throw ex
}
override fun fatalError(ex: SAXParseException) {
log.error(
"Problem at {}:{}:{} parsing deployment configuration: {}",
fileURL, ex.lineNumber, ex.columnNumber, ex.message
)
throw ex
}
}
private fun disableProperty(dbf: DocumentBuilderFactory, propertyName: String) {
try {
dbf.setAttribute(propertyName, "")
} catch (iae: IllegalArgumentException) {
// Property not supported.
}
}
private fun disableProperty(sf: SchemaFactory, propertyName: String) {
try {
sf.setProperty(propertyName, "")
} catch (ex: SAXNotRecognizedException) {
// Property not supported.
} catch (ex: SAXNotSupportedException) {
}
}
private fun getSchema(schemaResourceURL: String): Schema {
val sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI)
sf.setFeature(FEATURE_SECURE_PROCESSING, true)
disableProperty(sf, ACCESS_EXTERNAL_SCHEMA)
disableProperty(sf, ACCESS_EXTERNAL_DTD)
val schemaUrl: URL = Xml::class.java.classLoader.getResource(schemaResourceURL)
?: throw IllegalStateException(String.format("Missing configuration schema '%s'", schemaResourceURL))
return sf.newSchema(schemaUrl)
}
private fun newDocumentBuilderFactory(schemaResourceURL: String?): DocumentBuilderFactory {
val dbf = DocumentBuilderFactory.newInstance()
dbf.setFeature(FEATURE_SECURE_PROCESSING, true)
disableProperty(dbf, ACCESS_EXTERNAL_SCHEMA)
disableProperty(dbf, ACCESS_EXTERNAL_DTD)
dbf.isExpandEntityReferences = false
dbf.isIgnoringComments = true
dbf.isNamespaceAware = true
val sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI)
sf.setFeature(FEATURE_SECURE_PROCESSING, true)
disableProperty(sf, ACCESS_EXTERNAL_SCHEMA)
disableProperty(sf, ACCESS_EXTERNAL_DTD)
if (schemaResourceURL != null) {
dbf.schema = getSchema(schemaResourceURL)
}
return dbf
}
fun newDocumentBuilder(resource: URL, schemaResourceURL: String?): DocumentBuilder {
val db = newDocumentBuilderFactory(schemaResourceURL).newDocumentBuilder()
db.setErrorHandler(XmlErrorHandler(resource))
return db
}
fun parseXmlResource(resource: URL, schemaResourceURL: String?): Document {
val db = newDocumentBuilder(resource, schemaResourceURL)
return resource.openStream().use(db::parse)
}
fun newDocumentBuilder(resource: URL): DocumentBuilder {
val db = newDocumentBuilderFactory(null).newDocumentBuilder()
db.setErrorHandler(XmlErrorHandler(resource))
return db
}
fun parseXmlResource(resource: URL): Document {
val db = newDocumentBuilder(resource, null)
return resource.openStream().use(db::parse)
}
}

View File

@@ -4,5 +4,6 @@ handlers = java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = FINEST java.util.logging.ConsoleHandler.level = FINEST
java.util.logging.ConsoleHandler.filter = java.util.logging.ConsoleHandler.filter =
java.util.logging.ConsoleHandler.formatter = java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format = %1$tF %1$tT [%4$s] %2$s %5$s %n
java.util.logging.ConsoleHandler.encoding = java.util.logging.ConsoleHandler.encoding =

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<server xmlns="urn:gradle-build-cache-server">
<bind host="127.0.0.1" port="5680"/>
<cache path="/tmp/gbcs"/>
<groups>
<readers>
<!-- <user name="reader"/>-->
</readers>
<writers>
<!-- <user name="writer"/>-->
</writers>
</groups>
<tls name=""/>
</server>

View File

@@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema elementFormDefault="qualified" targetNamespace="urn:gradle-build-cache-server" version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:gbcs="urn:gradle-build-cache-server">
<xs:element name="server" type="gbcs:serverType"/>
<xs:complexType name="serverType">
<xs:sequence minOccurs="0">
<xs:element name="bind" type="gbcs:bindType"/>
<xs:element name="cache" type="gbcs:cacheDirType"/>
<xs:element name="groups" type="gbcs:groupsType"/>
<xs:element name="tls" type="gbcs:tlsType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="bindType">
<xs:attribute name="host" type="xs:string" use="required"/>
<xs:attribute name="port" type="xs:unsignedShort" use="required"/>
</xs:complexType>
<xs:complexType name="cacheDirType">
<xs:attribute name="path" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="groupsType">
<xs:all>
<xs:element name="readers" type="gbcs:groupType"/>
<xs:element name="writers" type="gbcs:groupType"/>
</xs:all>
</xs:complexType>
<xs:complexType name="groupType">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="user" type="gbcs:userType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="userType">
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="tlsType">
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="instancesType">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="instance" type="contour:instanceType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="instanceType">
<xs:all>
<xs:element name="database" type="contour:databaseType"/>
<xs:element name="application-properties" type="contour:propertiesType"/>
<xs:element name="corda-node" type="contour:cordaNodeType" minOccurs="0" maxOccurs="1"/>
</xs:all>
<xs:attribute name="name" type="xs:token" use="required"/>
</xs:complexType>
<xs:complexType name="propertiesType">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="property" type="contour:propertyType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="propertyType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="key" type="xs:string" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="servicesType">
<xs:all>
<xs:element name="postgresDatabase" type="contour:postgresDatabaseType"/>
<xs:element name="mailhogServer" type="contour:mailhogServerType"/>
</xs:all>
</xs:complexType>
<xs:complexType name="hostAndPortType">
<xs:attribute name="host" type="xs:string" use="required"/>
<xs:attribute name="port" type="xs:unsignedShort" use="required"/>
</xs:complexType>
<xs:complexType name="postgresDatabaseType">
<xs:all>
<xs:element name="container-name" type="xs:token"/>
<xs:element name="port" type="xs:unsignedShort"/>
<xs:element name="password" type="xs:token"/>
<xs:element name="image" type="xs:token"/>
</xs:all>
</xs:complexType>
<xs:complexType name="mailhogServerType">
<xs:all>
<xs:element name="container-name" type="xs:token"/>
<xs:element name="http-port" type="xs:unsignedShort"/>
<xs:element name="smtp-port" type="xs:unsignedShort"/>
<xs:element name="image" type="xs:token"/>
</xs:all>
</xs:complexType>
<xs:complexType name="codeType">
<xs:all>
<xs:element name="front-end" type="contour:codeRepositoryType"/>
<xs:element name="back-end" type="contour:codeRepositoryType"/>
<xs:element name="cordapps" type="contour:codeRepositoryType"/>
</xs:all>
</xs:complexType>
<xs:complexType name="codeRepositoryType">
<xs:attribute name="location" type="xs:token" use="required"/>
</xs:complexType>
<xs:complexType name="databaseType">
<xs:all>
<xs:element name="url" type="xs:string"/>
<xs:element name="name">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string"/>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
<xs:complexType name="urlType">
<xs:simpleContent>
<xs:extension base="xs:string"/>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="jvmType">
<xs:attribute name="location" type="xs:token" use="required"/>
</xs:complexType>
<xs:complexType name="artifactsType">
<xs:all>
<xs:element name="contract-cordapp" type="contour:mavenArtifactType"/>
<xs:element name="workflow-cordapp" type="contour:mavenArtifactType"/>
<xs:element name="business-tool-cordapp" type="contour:mavenArtifactType"/>
<xs:element name="spring-backend" type="contour:mavenArtifactType"/>
</xs:all>
</xs:complexType>
<xs:complexType name="mavenArtifactType">
<xs:attribute name="groupId" type="xs:string" use="required"/>
<xs:attribute name="artifactId" type="xs:string" use="required"/>
<xs:attribute name="version" type="xs:string" use="required"/>
<xs:attribute name="ext" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="cordaNodeType">
<xs:choice>
<xs:element name="config" type="contour:simpleCordaConfigType"/>
<xs:element name="configFile" type="xs:string"/>
</xs:choice>
<xs:attribute name="x500Name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="rpcUsersType">
<xs:sequence>
<xs:element name="user" type="contour:rpcUserType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="rpcUserType">
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="password" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="simpleCordaConfigType">
<xs:all>
<xs:element name="h2Port" type="xs:unsignedShort"/>
<xs:element name="devMode" type="xs:boolean"/>
<xs:element name="p2p-address" type="contour:hostAndPortType"/>
<xs:element name="rpc-address" type="contour:hostAndPortType"/>
<xs:element name="rpc-admin-address" type="contour:hostAndPortType"/>
<xs:element name="rpc-users" type="contour:rpcUsersType"/>
</xs:all>
</xs:complexType>
</xs:schema>